import React, { ReactNode } from 'react';
import { Renderer, RendererProps } from '../factory';
import { Action, Schema, SchemaNode } from '../types';
import find from 'lodash/find';
import {
  isVisible,
  autobind,
  isDisabled,
  isObject,
  createObject,
  getVariable
} from '../utils/helper';
import findIndex from 'lodash/findIndex';
import { Tabs as CTabs, Tab } from '../components/Tabs';
import { ClassNamesFn } from '../theme';
import {
  BaseSchema,
  SchemaClassName,
  SchemaCollection,
  SchemaIcon
} from '../Schema';
import { ActionSchema } from './Action';
import { filter } from '../utils/tpl';
import {
  resolveVariable,
  tokenize,
  resolveVariableAndFilter
} from '../utils/tpl-builtin';
import { FormSchemaHorizontal } from './Form/index';
import { str2AsyncFunction } from '../utils/api';
import { IScopedContext, ScopedContext } from '../Scoped';
import { tools } from '../utils/shell/tools';
import { isNil } from 'lodash';
import { message } from 'antd';

export interface TabSchema extends Omit<BaseSchema, 'type'> {
  /**
   * Tab 标题
   */
  title?: string;

  /**
   * 内容
   * @deprecated 用 body 属性
   */
  tab?: SchemaCollection;

  /**
   * 内容
   */
  body?: SchemaCollection;

  /**
   * 徽标
   */
  badge?: number;

  /**
   * 设置以后将跟url的hash对应
   */
  hash?: string;

  /**
   * 按钮图标
   */
  icon?: SchemaIcon;

  iconPosition?: 'left' | 'right';

  /**
   * 设置以后内容每次都会重新渲染
   */
  reload?: boolean;

  /**
   * 点开时才加载卡片内容
   */
  mountOnEnter?: boolean;

  /**
   * 卡片隐藏就销毁卡片节点。
   */
  unmountOnExit?: boolean;

  /**
   * 配置子表单项默认的展示方式。
   */
  mode?: 'normal' | 'inline' | 'horizontal';
  /**
   * 如果是水平排版，这个属性可以细化水平排版的左右宽度占比。
   */
  horizontal?: FormSchemaHorizontal;

  isTotalMode?: boolean;
  tabName: string;
}

/**
 * 选项卡控件。
 * 文档：https://baidu.gitee.io/amis/docs/components/tabs
 */
export interface TabsSchema extends BaseSchema {
  type: 'tabs';

  /**
   * 选项卡成员。当配置了 source 时，选项卡成员，将会根据目标数据进行重复。
   */
  tabs: Array<TabSchema>;

  /**
   * 关联已有数据，选项卡直接根据目标数据重复。
   */
  source?: string;

  /**
   * 类名
   */
  tabsClassName?: SchemaClassName;

  /**
   * 展示形式
   */
  tabsMode?: '' | 'line' | 'card' | 'radio' | 'vertical' | 'tiled' | 'content-tiled';

  /**
   * 内容类名
   */
  contentClassName?: SchemaClassName;

  /**
   * 链接外层类名
   */
  linksClassName?: SchemaClassName;

  /**
   * 卡片是否只有在点开的时候加载，暂时不需要这个了，因为改成内部tab自己控制
   */
  mountOnEnter?: boolean;

  /**
   * 卡片隐藏的时候是否销毁卡片内容
   */
  unmountOnExit?: boolean;

  /**
   * 可以在右侧配置点其他功能按钮。
   */
  toolbar?: ActionSchema;

  /**
   * 配置子表单项默认的展示方式。
   */
  subFormMode?: 'normal' | 'inline' | 'horizontal';
  /**
   * 如果是水平排版，这个属性可以细化水平排版的左右宽度占比。
   */
  subFormHorizontal?: FormSchemaHorizontal;
  /**
   * 是否支持溢出滚动
   */
  scrollable?: boolean;
  /**
   * 用于表单更新数据，以及更新数据域
   */
  name?: string;
}

export interface TabsProps
  extends RendererProps,
  Omit<TabsSchema, 'className' | 'contentClassName'> {
  activeKey?: string | number;
  location?: any;
  tabRender?: (tab: TabSchema, props: TabsProps, index: number) => JSX.Element;
}

export interface TabsState {
  activeKey: any;
  prevKey: any;
  dataField: object;//内部数据域
}

export default class Tabs extends React.Component<TabsProps, TabsState> {
  static defaultProps: Partial<TabsProps> = {
    className: '',
    mode: '',
    mountOnEnter: true,
    unmountOnExit: false,
    scrollable: true //Aug
  };

  renderTab?: (tab: TabSchema, props: TabsProps, index: number) => JSX.Element;
  activeKey: any;

  constructor(props: TabsProps) {
    super(props);

    const location = props.location || window.location;
    const tabs = props.tabs;
    let activeKey: any = 0;
    const collectedActiveTab = sessionStorage.getItem('collectedActiveTab')
    if (!isNil(collectedActiveTab)) {
      const collectedContent = JSON.parse(collectedActiveTab)
      let keyList = collectedContent.keyList as Array<number | string>;
      if (keyList.length) {
        const targetKey = keyList.pop()
        //如果查询到了，说明是使用tabName收藏
        const targetIndex = tabs.findIndex(item => item.tabName === targetKey)
        if (targetIndex === -1) {
          //这里判断tabName没有定位到的情况，要么是被删除，要么是使用下标进行收藏
          if (typeof targetKey == 'number' && tabs[targetKey]) {
            //说明定位成功
            if (tabs[targetKey].tabName === collectedContent.tabName) {
              activeKey = targetKey
            } else {
              //顺序改变，导致定位失败，则查找打开相同tabName的tab
              const getIndex = tabs.findIndex(item => item.tabName === collectedContent.tabName)
              if (getIndex !== -1) activeKey = getIndex
            }
          } else {
            message.info('该节点不存在，请检查是否已被删除')
            keyList = []
          }
        } else {
          activeKey = targetIndex
        }
        if (keyList.length > 0) {
          sessionStorage.setItem('collectedActiveTab', JSON.stringify({ ...collectedContent, keyList }))
        } else {
          sessionStorage.removeItem('collectedActiveTab')
        }
      }
    }
    if (typeof props.activeKey !== 'undefined') {
      activeKey = props.activeKey;
    } else if (location && Array.isArray(tabs)) {
      const hash = location.hash.substring(1);
      const tab: TabSchema = find(tabs, tab => tab.hash === hash) as TabSchema;

      if (tab) {
        activeKey = tab.hash;
      } else if (props.defaultActiveKey) {
        activeKey = tokenize(props.defaultActiveKey, props.data);
      } else {
        const show = isVisible(tabs[activeKey], props.data)
        if (show === false) {
          const showIndex = tabs.findIndex(tab => isVisible(tab, props.data))
          showIndex !== -1 && (activeKey = showIndex)
        }
      }

      activeKey = activeKey || (tabs[0] && tabs[0].hash) || 0;
    }

    this.state = {
      prevKey: undefined,
      activeKey: (this.activeKey = activeKey),
      dataField: {}
    };
  }

  componentDidMount() {
    this.autoJumpToNeighbour(this.activeKey);

    // let { name, value, onChange, source, tabs, data } = this.props;

    // // 如果没有配置 name ，说明不需要同步表单值
    // if (
    //   !name ||
    //   typeof onChange !== 'function' ||
    //   // 如果关联某个变量数据，则不启用
    //   source
    // ) {
    //   return;
    // }

    // value = value ?? getVariable(data, name);

    //  如果有值，切到对应的 tab
    // if (value && Array.isArray(tabs)) {
    //   const key = this.resolveKeyByValue(value);
    //   key !== undefined && this.handleSelect(key);
    // } else {
    //   const tab = this.resolveTabByKey(this.activeKey);
    //   if (tab && value !== ((tab as any).value ?? tab.title)) {
    //     onChange((tab as any).value ?? tab.title, name);
    //   }
    // }
  }

  componentDidUpdate(preProps: TabsProps, prevState: any) {
    const props = this.props;

    if (props.location && props.location.hash !== preProps.location.hash) {
      const hash = props.location.hash.substring(1);
      if (!hash) {
        return;
      }

      const tab: TabSchema = find(
        props.tabs,
        tab => tab.hash === hash
      ) as TabSchema;
      if (tab && tab.hash && tab.hash !== this.state.activeKey) {
        this.setState({
          activeKey: (this.activeKey = tab.hash),
          prevKey: this.state.activeKey
        });
      }
    } else if (
      Array.isArray(props.tabs) &&
      Array.isArray(preProps.tabs) &&
      JSON.stringify(props.tabs.map(item => item.hash)) !==
      JSON.stringify(preProps.tabs.map(item => item.hash))
    ) {
      let activeKey: any = this.state.activeKey;
      const location = props.location;
      let tab: TabSchema | null = null;

      if (location && Array.isArray(props.tabs)) {
        const hash = location.hash.substring(1);
        tab = find(props.tabs, tab => tab.hash === hash) as TabSchema;
      }

      if (tab) {
        activeKey = tab.hash;
      } else if (
        !props.tabs ||
        !props.tabs.some((item, index) =>
          item.hash ? item.hash === activeKey : index === activeKey
        )
      ) {
        activeKey = (props.tabs && props.tabs[0] && props.tabs[0].hash) || 0;
      }

      this.setState({
        prevKey: undefined,
        activeKey: (this.activeKey = activeKey)
      });
    }

    this.autoJumpToNeighbour(this.activeKey);

    // let { name, value, onChange, source, data } = this.props;

    // 如果没有配置 name ，说明不需要同步表单值
    // if (
    //   !name ||
    //   typeof onChange !== 'function' ||
    //   // 如果关联某个变量数据，则不启用
    //   source
    // ) {
    //   return;
    // }

    // let key: any;
    // value = value ?? getVariable(data, name);
    // const prevValue =
    //   preProps.value ?? getVariable(preProps.data, preProps.name);
    // if (
    //   value !== prevValue &&
    //   (key = this.resolveKeyByValue(value)) !== undefined &&
    //   key !== this.activeKey
    // ) {
    //   this.handleSelect(key);
    // } else if (this.activeKey !== prevState.activeKey) {
    //   const tab = this.resolveTabByKey(this.activeKey);
    //   if (tab && value !== ((tab as any).value ?? tab.title)) {
    //     onChange((tab as any).value ?? tab.title, name);
    //   }
    // }
  }

  resolveTabByKey(key: any) {
    const tabs = this.props.tabs;

    if (!Array.isArray(tabs)) {
      return;
    }

    return find(tabs, (tab: TabSchema, index) =>
      tab.hash ? tab.hash === key : index === key
    );
  }

  resolveKeyByValue(value: any) {
    const tabs = this.props.tabs;

    if (!Array.isArray(tabs)) {
      return;
    }

    const tab: TabSchema = find(
      tabs,
      tab => ((tab as any).value ?? tab.title) === value
    ) as TabSchema;

    return tab && tab.hash ? tab.hash : tabs.indexOf(tab);
  }

  autoJumpToNeighbour = (key: any) => {
    const { tabs, data } = this.props;

    if (!Array.isArray(tabs)) {
      return;
    }

    // 当前 tab 可能不可见，所以需要自动切到一个可见的 tab, 向前找，找一圈
    const tabIndex = findIndex(tabs, (tab: TabSchema, index) =>
      tab.hash ? tab.hash === key : index === key
    );
    const ctx = createObject(data, this.state.dataField)
    // Jay 增加form init请求初始化后数据更新后才判断isVisible的条件
    if (tabs[tabIndex] && !isVisible(tabs[tabIndex], ctx) && (this.props.formStore ? this.props.formStore.inited : true)) {
      const targetIndex = tabs.findIndex(tab => isVisible(tab, ctx))
      if (targetIndex !== -1) {
        this.setState({
          activeKey: (this.activeKey = targetIndex)
        })
      }
    }
  }

  handleSelect = (key: any) => {
    const { env, onSelect, id } = this.props;

    env.tracker?.({
      eventType: 'tabChange',
      eventData: {
        id,
        key
      }
    });

    // 是 hash，需要更新到地址栏
    if (typeof key === 'string' && env) {
      env.updateLocation(`#${key}`);
    } else if (typeof this.state.activeKey === 'string' && env) {
      env.updateLocation(`#`);
    }

    this.setState({
      activeKey: (this.activeKey = key),
      prevKey: this.state.activeKey
    });

    if (typeof onSelect === 'string') {
      const selectFunc = str2AsyncFunction(onSelect, 'key', 'props');
      selectFunc && selectFunc(key, this.props);
    } else if (typeof onSelect === 'function') {
      onSelect(key, this.props);
    }
  }

  switchTo = (index: number) => {
    const { tabs } = this.props;

    Array.isArray(tabs) &&
      tabs[index] &&
      this.setState({
        activeKey: (this.activeKey = tabs[index].hash || index)
      });
  }

  currentIndex = (): number => {
    const { tabs } = this.props;

    return Array.isArray(tabs)
      ? findIndex(tabs, (tab: TabSchema, index) =>
        tab.hash
          ? tab.hash === this.state.activeKey
          : index === this.state.activeKey
      )
      : -1;
  }

  renderToolbar() {
    const { toolbar, render, classnames: cx, toolbarClassName } = this.props;

    return toolbar ? (
      <div className={cx(`Tabs-toolbar`, toolbarClassName)}>
        {render('toolbar', toolbar)}
      </div>
    ) : null;
  }
  handleReload(children: ReactNode) { }

  getTabsActiveKeys() { }

  renderTabs() {
    const {
      classnames: cx,
      classPrefix: ns,
      contentClassName,
      linksClassName,
      tabRender,
      className,
      render,
      data,
      mode: dMode,
      tabsMode,
      unmountOnExit,
      source,
      formStore,
      formMode,
      formHorizontal,
      subFormMode,
      subFormHorizontal,
      scrollable,
      notPrintFieldList
    } = this.props;

    const mode = tabsMode || dMode;
    const values = createObject(data, this.state.dataField);
    const arr = resolveVariableAndFilter(source, values, '| raw');
    // let mountOnEnter = this.props.mountOnEnter;
    let tabs = this.props.tabs;
    if (!tabs) {
      return null;
    }

    tabs = Array.isArray(tabs) ? tabs : [tabs];
    let children: Array<JSX.Element | null> = [];
    if (Array.isArray(arr)) {
      arr.forEach((value, index) => {
        const ctx = createObject(
          values,
          isObject(value) ? { index, ...value } : { item: value, index }
        );

        children.push(
          ...tabs.map((tab, tabIndex) =>
            isVisible(tab, ctx) ? (
              <Tab
                {...(tab as any)}
                title={filter(tab.title, ctx)}
                disabled={isDisabled(tab, ctx)}
                key={`${index * 1000 + tabIndex}`}
                eventKey={index * 1000 + tabIndex}
                isTotalMode={tab?.isTotalMode}
                unmountOnExit={
                  typeof tab.reload === 'boolean'
                    ? tab.reload
                    : typeof tab.unmountOnExit === 'boolean'
                      ? tab.unmountOnExit
                      : unmountOnExit
                }
              >
                {

                  (setTotalNum: any, totalTab: any) => render(
                    `item/${index}/${tabIndex}`,
                    (tab as any)?.type ? (tab as any) : tab.tab || tab.body,
                    {
                      data: ctx,
                      setTotalNum: setTotalNum,
                      totalTab,
                      formMode: tab.mode || subFormMode || formMode,
                      formHorizontal:
                        tab.horizontal || subFormHorizontal || formHorizontal,
                      mountOnEnter: tab.mountOnEnter
                    }
                  )
                }
              </Tab>
            ) : null
          )
        );
      });
    } else {
      children = tabs.map((tab, index) => {
        return isVisible(tab, values) ? (
          <Tab
            {...(tab as any)}
            title={filter(tab.title, values)}
            disabled={isDisabled(tab, values)}
            key={index}
            isTotalMode={tab.isTotalMode}
            eventKey={tab.hash || index}
            unmountOnExit={
              typeof tab.reload === 'boolean'
                ? tab.reload
                : typeof tab.unmountOnExit === 'boolean'
                  ? tab.unmountOnExit
                  : unmountOnExit
            }
          >

            {
              tab?.isTotalMode ? (setTotalNum: any, totalTab: any) => render(
                `tab/${index}`,
                (tab as any)?.type ? (tab as any) : tab.tab || tab.body,
                {
                  setTotalNum: setTotalNum,
                  totalTab,
                  formMode: tab.mode || subFormMode || formMode,
                  formHorizontal:
                    tab.horizontal || subFormHorizontal || formHorizontal,
                  // Jay
                  // 表单下多个tab页的service组件一起发起请求时loading的控制，当activeKey的tab请求才设置loading
                  markFetching: this.state.activeKey === tab.hash || this.state.activeKey === index,
                  defer: this.state.activeKey !== tab.hash && this.state.activeKey !== index,
                  tabTitle: tab.title,
                  mountOnEnter: tab.mountOnEnter
                }
              ) : this.renderTab
                ? this.renderTab(tab, this.props, index)
                : tabRender
                  ? tabRender(tab, this.props, index)
                  : render(
                    `tab/${index}`,
                    (tab as any)?.type ? (tab as any) : tab.tab || tab.body,
                    {
                      formMode: tab.mode || subFormMode || formMode,
                      formHorizontal:
                        tab.horizontal || subFormHorizontal || formHorizontal,
                      // Jay
                      // 表单下多个tab页的service组件一起发起请求时loading的控制，当activeKey的tab请求才设置loading
                      markFetching: this.state.activeKey === tab.hash || this.state.activeKey === index,
                      tabsdefer: tab.mountOnEnter ? 0 : this.state.activeKey !== tab.hash && this.state.activeKey !== index,
                      tabTitle: tab.title,
                      mountOnEnter: tab.mountOnEnter
                    }
                  )}
          </Tab>
        ) : null
      });
    }

    return (
      <CTabs
        classPrefix={ns}
        classnames={cx}
        mode={mode}
        data={this.props.data}
        className={className}
        contentClassName={contentClassName}
        linksClassName={linksClassName}
        onSelect={this.handleSelect}
        activeKey={this.state.activeKey}
        toolbar={this.renderToolbar()}
        scrollable={scrollable}
        env={this.props?.env}
        useMobileUI={this.props?.useMobileUI} //Aug
        handleReload={this.handleReload}
        getTabsActiveKeys={this.getTabsActiveKeys}
        notPrintFieldList={notPrintFieldList}
      >
        {children}
      </CTabs>
    );
  }

  reload = (subPath?: string, query?: any, ctx?: any) => {
    if (ctx) {
      this.setState({ dataField: ctx })
    }
  }

  render() {
    return this.renderTabs();
  }
}
@Renderer({
  type: 'tabs'
})
export class TabsRenderer extends Tabs {
  static contextType = ScopedContext;

  constructor(props: TabsProps, context: IScopedContext) {
    super(props);

    const scoped = context;
    scoped.registerComponent(this);
  }

  componentWillUnmount() {
    const scoped = this.context as IScopedContext;
    scoped.unRegisterComponent(this);
  }

  getTabsActiveKeys = () => {
    let keyList = [this.props.tabs[this.state.activeKey].tabName];
    const scoped = this.context as IScopedContext;
    function fabScoped(currentScoped: IScopedContext) {
      const tabItem = currentScoped.getComponents().find(item => item.props.type === 'tabs')
      if (tabItem && !isNil((tabItem as any)?.activeKey)) {
        keyList.push(tabItem.props.tabs[(tabItem as any).activeKey].tabName)
      }
      for (let i = 0; i < 100; i++) {
        if (currentScoped.parent) {
          fabScoped(currentScoped.parent)
        } else {
          break
        }
      }
    }
    scoped.parent && fabScoped(scoped.parent)
    return keyList
  }

  handleReload = (children: ReactNode) => {
    const scoped = this.context as IScopedContext;
    if (tools.isArray(children)) {
      children.forEach((child: any) => {
        const serviceSchema = child.props.body;
        if (tools.isArray(serviceSchema)) {
          serviceSchema.forEach(item => {
            if (item.type === 'service') {
              const component = item.name && scoped.getComponentByName(item.name)
              component?.reload()
            }
          })
        } else if (serviceSchema.type === 'service') {
          const component = serviceSchema.name && scoped.getComponentByName(serviceSchema.name)
          component?.reload()
        }
      })
    }
  }
}
