import React, { createContext, useState, useContext, useMemo } from 'react';
import { useCreation, useMemoizedFn } from 'ahooks';
import { withoutTrailingSlash } from 'ufo';
import isPlainObject from 'lodash/isPlainObject';
import { WELLKNOWN_BLOCKLET_ADMIN_PATH } from '@abtnode/constant';
import { Locale } from '@arcblock/ux/lib/type';
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
import { AppBadgeProps } from './app-badge';

export type NavItem = {
  id: string;
  parent: string; // pid
  title: string;
  link: string;
  description?: string;
};

export interface TabConfig {
  value: string;
  label?: string;
  render?: React.ComponentType | React.ReactNode;
}

export interface AppInfo {
  icon?: React.ReactNode;
  name?: React.ReactNode;
  description?: React.ReactNode;
  badges?: Array<AppBadgeProps | React.ReactElement>;
  actions?: React.ReactNode;
  tabs?: TabConfig[];
  currentTab?: string;
}

export interface AppInfoContextValue extends AppInfo {
  inService: boolean;
  currentTab: string;
  TabComponent: React.ComponentType | React.ReactNode;
  navItem?: NavItem;
  updateAppInfo: (patch: Partial<AppInfo>) => void;
}

const AppInfoContext = createContext<AppInfoContextValue>({
  inService: false,
  currentTab: '',
  TabComponent: null,
  navItem: undefined,
  updateAppInfo: () => {},
});

export const getI18nVal = (
  obj: Record<string, string | Record<Locale, string>>,
  key: string,
  locale: Locale = 'en'
) => {
  const val = obj?.[key];

  // @ts-ignore
  return isPlainObject(val) ? val[locale] || val.en : val;
};

// 基于前缀匹配算法查找 NavItem
export const findNavItem = (items: NavItem[], targetLink: string = '', locale: Locale = 'en') => {
  const targetParts = targetLink === '/' ? ['/'] : targetLink.split('/').filter(Boolean);

  let result: NavItem | null = null;
  let maxLen = 0;

  items.forEach((item) => {
    const currentLink = getI18nVal(item, 'link', locale) || '';
    const currentParts = currentLink === '/' ? ['/'] : currentLink.split('/').filter(Boolean);

    if (currentParts.length > targetParts.length) {
      return;
    }

    let isMatch = true;
    for (let i = 0; i < currentParts.length; i++) {
      if (currentParts[i] !== targetParts[i]) {
        isMatch = false;
        break;
      }
    }

    if (isMatch && currentParts.length > maxLen) {
      result = item;
      maxLen = currentParts.length;
    }
  });

  return result;
};

interface AppInfoProviderProps {
  path?: string;
  currentTab?: string;
  meta?: object;
  children?: React.ReactNode;
}
export function AppInfoProvider({
  path = window?.location?.pathname || '',
  currentTab = '',
  meta = undefined,
  children = null,
}: AppInfoProviderProps) {
  const { locale = 'en' } = useLocaleContext() || {};
  const targetLink = withoutTrailingSlash(path);
  const inService = targetLink.startsWith(WELLKNOWN_BLOCKLET_ADMIN_PATH);
  // 便于测试
  const blockletMeta = useCreation(() => Object.assign({}, window.blocklet, meta), [meta]);

  // 匹配 Dashboard NavItem
  const navItem = useCreation(() => {
    // @ts-ignore
    const navigations = blockletMeta.navigation?.filter((v) =>
      Array.isArray(v.section) ? v.section.includes('dashboard') : v.section === 'dashboard'
    );
    const items: NavItem[] = navigations?.flatMap((v: { items?: NavItem[] }) => v.items || []);
    // 前缀匹配 navItem
    const item = findNavItem(items, targetLink, locale);

    if (!item) {
      return undefined;
    }

    const parentItem = navigations.find((v: NavItem) => v.id === item.parent);
    let title = getI18nVal(item, 'title', locale) || '';

    if (!inService) {
      // 应用带上父级标题
      title = `${getI18nVal(parentItem, 'title', locale) || ''} - ${title}`;
    }

    return {
      id: item.id,
      parent: item.parent,
      title,
      link: getI18nVal(item, 'link', locale) || '',
      description: getI18nVal(item, 'description', locale) || '',
    } as NavItem;
  }, [path, inService, locale, blockletMeta]);

  const [appInfo, setAppInfo] = useState<AppInfo>({});

  const updateAppInfo = useMemoizedFn((patch: Partial<AppInfo>) => {
    setAppInfo((prev) => ({ ...prev, ...patch }));
  });

  const value = useMemo(
    () => {
      const { tabs = [] } = appInfo;
      const currentTabConfig = tabs.find((v) => v.value === currentTab);

      let ctab = currentTab;
      let TabComponent = null;
      // fallback 到第一个 tab
      if (!currentTabConfig && tabs.length > 0) {
        ctab = tabs[0].value;
        TabComponent = tabs[0].render || null;
      } else {
        TabComponent = currentTabConfig?.render || null;
      }

      return {
        ...appInfo,
        inService,
        navItem,
        currentTab: ctab,
        TabComponent,
        updateAppInfo,
      };
    },
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [appInfo, navItem, inService, currentTab, updateAppInfo]
  );

  return <AppInfoContext.Provider value={value}>{children}</AppInfoContext.Provider>;
}

export function useAppInfo(): AppInfoContextValue {
  const context = useContext(AppInfoContext);
  return context;
}
