/**
 * 级联多选框，支持无限极。从左侧到右侧一层层点选。
 */
import { BaseSelection, BaseSelectionProps } from './Selection';
import { themeable } from '../theme';
import React from 'react';
import { uncontrollable } from 'uncontrollable';
import Checkbox from './Checkbox';
import { Option } from './Select';
import { getTreeDepth, isMobile } from '../utils/helper';
import times from 'lodash/times';
import Spinner from './Spinner';
import { localeable } from '../locale';
import { Tabs } from 'antd';
import { CheckOutlined, CloseCircleFilled } from '@ant-design/icons';
import isEqual from 'lodash/isEqual';

export interface ChainedSelectionProps extends BaseSelectionProps {
  defaultSelectedIndex?: string | string[];
}

export interface ChainedSelectionState {
  selected: Array<string>;
  ActiveKey?: string;
}

export class ChainedSelection extends BaseSelection<
  ChainedSelectionProps,
  ChainedSelectionState
> {
  valueArray: Array<Option>;
  state: ChainedSelectionState = {
    selected: [],
    ActiveKey: "default"
  };
  dom: HTMLDivElement
  componentDidMount() {
    const defaultSelectedIndex = this.props.defaultSelectedIndex;

    if (defaultSelectedIndex !== undefined) {
      this.setState({
        selected: Array.isArray(defaultSelectedIndex) ? [...defaultSelectedIndex] : [defaultSelectedIndex]
      });
    }
  }
  componentDidUpdate(prevProps: ChainedSelectionProps) {
    const defaultSelectedIndex = this.props.defaultSelectedIndex;

    if (defaultSelectedIndex !== undefined && defaultSelectedIndex !== prevProps.defaultSelectedIndex) {
      this.setState({
        selected: Array.isArray(defaultSelectedIndex) ? [...defaultSelectedIndex] : [defaultSelectedIndex]
      });
    }
  }

  selectOption(option: Option, depth: number, id: string) {
    const { onDeferLoad } = this.props;
    const selected = this.state.selected.concat();
    selected.splice(depth, selected.length - depth);
    selected.push(id);

    this.setState(
      {
        selected,
        ActiveKey: "default"
      }, () => {
        option.defer && onDeferLoad ? () => onDeferLoad(option) : undefined;
        if (this.dom) this.handleLeft(this.dom.offsetWidth, selected.length)
      }
    );
  }

  renderItem(option: Option, index: number, depth: number, id: string) {
    const {
      labelClassName,
      disabled,
      classnames: cx,
      itemClassName,
      itemRender,
      multiple
    } = this.props;
    const valueArray = this.valueArray;

    return (
      <div
        key={index}
        className={cx(
          'ChainedSelection-item',
          itemClassName,
          option.className,
          disabled || option.disabled ? 'is-disabled' : '',
          !!~valueArray.indexOf(option) ? 'is-active' : ''
        )}
        onClick={() => this.toggleOption(option)}
      >
        <div className={cx('ChainedSelection-itemLabel')}>
          {itemRender(option, {
            index: index,
            multiple: multiple,
            checked: !!~valueArray.indexOf(option),
            onChange: () => this.toggleOption(option),
            disabled: disabled || option.disabled
          })}
        </div>

        {multiple ? (
          <Checkbox
            size="sm"
            checked={!!~valueArray.indexOf(option)}
            disabled={disabled || option.disabled}
            labelClassName={labelClassName}
            description={option.description}
          />
        ) : null}
      </div>
    );
  }

  renderOption(option: Option, index: number, depth: number, id: string) {
    const {
      disabled,
      classnames: cx,
      itemClassName,
      itemRender,
      multiple
    } = this.props;

    if (Array.isArray(option.children) || option.defer) {
      return (
        <div
          key={index}
          className={cx(
            'ChainedSelection-item',
            itemClassName,
            option.className,
            disabled || option.disabled ? 'is-disabled' : '',
            ~this.state.selected.indexOf(id) ? 'is-active' : ''
          )}
          onClick={() => this.selectOption(option, depth, id)}
        >
          <div className={cx('ChainedSelection-itemLabel')}>
            {itemRender(option, {
              index: index,
              multiple: multiple,
              checked: !!~this.state.selected.indexOf(id),
              onChange: () => this.selectOption(option, depth, id),
              disabled: disabled || option.disabled
            })}
          </div>

          {option.defer && option.loading ? <Spinner size="sm" show /> : null}
          {(isMobile() && ~this.state.selected.indexOf(id)) ? <CheckOutlined style={{ color: '#1890ff' }} /> : ''}
        </div>
      );
    }

    return this.renderItem(option, index, depth, id);
  }
  renderOptionTabs = () => {
    const { options } = this.props
    const { selected } = this.state
    if (!selected.length) {
      return [0].map(() => <Tabs.TabPane tab={'请选择'} key={'default'} ></Tabs.TabPane>
      )
    } else {
      return [selected.map((item) => {
        if (item.includes('-')) {
          const tabLabel = this.getNestedValue(options, item).label
          return <Tabs.TabPane tab={tabLabel} key={item} ></Tabs.TabPane>
        } else {
          return <Tabs.TabPane tab={options[item].label} key={item} ></Tabs.TabPane>
        }
      }), <Tabs.TabPane tab={'请选择'} key={'default'} ></Tabs.TabPane>]
    }
  }
  getNestedValue(arr: Option, index: string) {
    let result = arr
    const indexes = index.split('-');
    indexes.forEach((item, index) => {
      if (result && result[item]?.children && index + 1 !== indexes.length) {
        result = result[item]?.children;
      } else {
        result = result[item]
      }
    })
    return result;
  }

  domRef = (ref: HTMLDivElement) => {
    this.dom = ref;
  };

  handleTabClick = (key: string) => {
    const { selected } = this.state
    this.setState({ ActiveKey: key }, () => {
      if (this.dom) this.handleLeft(this.dom.offsetWidth, selected.indexOf(key) !== -1 ? selected.indexOf(key) : selected.length)
    })
  }

  handleLeft = (width: number, select: number) => {
    this.dom?.scrollTo({ left: width * select })
  }
  // 可已挖掘深层
  findAncestors = (targetValue: Option, orgArray: Option[]) => {
    for (const orgItem in orgArray) {
      const result = this.findAncestorsRecursive(orgItem, orgArray, targetValue, []);
      if (result && result?.length > 0) {
        return result.map((value: string, index: number) => {
          return result.slice(0, index + 1).join('-');
        });
      }
    }
    return [];
  }

  findAncestorsRecursive: any = (node: number, orgArray: Option[], targetValue: Option, path: any[]) => {
    if (!orgArray[node]) {
      return [];
    }
    // 将当前节点的value添加到路径中
    path.push(node);
    if (isEqual(orgArray[node], targetValue)) {
      return path;
    }

    if (orgArray[node]?.children) {
      for (const child in orgArray[node]?.children) {
        const result = this.findAncestorsRecursive(child, orgArray[node]?.children, targetValue, [...path]);
        if (result && result?.length > 0) {
          return result;
        }
      }
    }
    return []
  }

  render() {
    const {
      value,
      options,
      className,
      placeholder,
      classnames: cx,
      option2value,
      multiple,
      translate: __
    } = this.props;
    const { ActiveKey } = this.state
    this.valueArray = BaseSelection.value2array(value, options, option2value);
    let body: Array<React.ReactNode> = [];

    if (Array.isArray(options) && options.length) {
      const selected: Array<string | null> = this.state.selected.concat();
      const depth = Math.min(getTreeDepth(options), 3);
      if(getTreeDepth(options) - selected.length > 0) {
        times(Math.max(depth - selected.length, 1), () => selected.push(null));
      }
      selected.reduce(
        (
          {
            body,
            options,
            subTitle,
            indexes,
            placeholder
          }: {
            body: Array<React.ReactNode>;
            options: Array<Option> | null;
            subTitle?: string;
            indexes: Array<number>;
            placeholder?: string;
          },
          selected,
          depth
        ) => {
          let nextOptions: Array<Option> = [];
          let nextSubTitle: string = '';
          let nextPlaceholder: string = '';
          let nextIndexes = indexes;

          body.push(
            <div key={depth} className={cx('ChainedSelection-col')}>
              {subTitle ? (
                <div className={cx('ChainedSelection-subTitle')}>
                  {subTitle}
                </div>
              ) : null}
              {Array.isArray(options) && options.length ? (
                options.map((option, index) => {
                  const id = indexes.concat(index).join('-');
                  if (id === selected) {
                    nextSubTitle = option.subTitle;
                    nextOptions = option.children!;
                    nextIndexes = indexes.concat(index);
                    nextPlaceholder = option.placeholder;
                  }
                  return this.renderOption(option, index, depth, id);
                })
              ) : (
                <div className={cx('ChainedSelection-placeholder')}>
                  {__(placeholder)}
                </div>
              )}
            </div>
          );

          return {
            options: nextOptions,
            subTitle: nextSubTitle,
            placeholder: nextPlaceholder,
            indexes: nextIndexes,
            body: body
          };
        },
        {
          options,
          body,
          indexes: [],
          placeholder
        }
      );
    }
    const content = body && body.length ? (
      body
    ) : (
      <div className={cx('ChainedSelection-placeholder')}>
        {__(placeholder)}
      </div>
    )
    //  this.renderOptionTabs(this.findAncestors(value[0], options)
    return (
      <div className={cx('ChainedSelection', className, isMobile() ? 'ChainedSelection-isModle' : '')}>
        {isMobile() ? <>
          <div className={cx('ChainedSelection-Tabs')} >
            <Tabs defaultActiveKey={'0'} activeKey={ActiveKey} onTabClick={this.handleTabClick}>
              {this.renderOptionTabs()}
            </Tabs>
          </div>
          <div className={cx('ChainedSelection-Checked', multiple ? 'ChainedSelection-Multiple' : '')} ref={this.domRef}>
            {content}
            {multiple && <div className={cx('ChainedSelection-Content')}>
              {this.props.value?.map((item: any) =>
                <div className={cx('ChainedSelection-value')}>
                  <span className={cx('ChainedSelection-label')}>
                    {item.label}
                  </span>
                  <span className={cx('ChainedSelection-Icon')}>
                    <CloseCircleFilled onClick={() => { this.toggleOption(item) }} />
                  </span>
                </div>
              )}
            </div>}
          </div>
        </> :
          content}

      </div >
    );
  }
}

export default themeable(
  localeable(
    uncontrollable(ChainedSelection, {
      value: 'onChange'
    })
  )
);
