import {
  Cascader as AntdCascader,
  CascaderProps,
  ConfigProvider,
  SelectProps,
} from 'antd';
import React, {
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useState,
} from 'react';
import './index.less';
import classNames from 'classnames';
import { DefaultOptionType } from 'antd/lib/cascader';
import { CascaderRef } from 'antd/lib/cascader';
import { Icon } from '../Icon';
import { AOP } from '../utils/AOP';
import { translate } from '../utils/index';

interface CascaderExtraProps {
  regionType?: 'province' | 'city' | 'country';
  regionCodes?: (number | string)[];
}

interface Option {
  value: string;
  label: string;
  children?: Option[];
  isLeaf?: boolean;
  loading?: boolean;
}

const Cascader = (
  props: React.PropsWithChildren<CascaderProps<DefaultOptionType>> & {
    ref?: React.Ref<CascaderRef> | undefined;
  } & CascaderExtraProps,
) => {
  const { locale } = useContext(ConfigProvider.ConfigContext);
  const [_value, setValue] = useState<any[]>(props.defaultValue);

  const [regionOptions, setRegionOptions] = useState<DefaultOptionType[]>();
  const Region = require('china-region');
  const regionLoop = {
    province: { getFn: Region.getPrefectures, type: 'city' },
    city: { getFn: Region.getCounties, type: 'country' },
  };

  const FormatOption = useCallback(
    (
      option: { name: string; code: string }[],
      type: string,
      selectOption?: any,
    ) => {
      const derictCity: any = {
        110000: '110100',
        120000: '120100',
        500000: '500100',
        310000: '310100',
      };
      const defaultAllRegionMap = {
        province: {
          label: translate(
            'packages.base.src.Cascader.index.全国',
            locale?.locale,
          ),
          value: '100000',
          isLeaf: true,
          type: 'all',
        },
        city: {
          label: translate(
            'packages.base.src.Cascader.index.全省',
            locale?.locale,
          ),
          value: selectOption?.value,
          isLeaf: true,
          type: 'all',
        },
        country: {
          label: translate(
            'packages.base.src.Cascader.index.全市',
            locale?.locale,
          ),
          value: selectOption?.value,
          isLeaf: true,
          type: 'all',
        },
      };
      let res = [];
      if (option.length === 0) {
        res = [
          {
            label: Region.info(selectOption?.value).name,
            value: derictCity[selectOption?.value],
            isLeaf: props.regionType === type,
            type,
          },
        ];
      } else {
        res = option.map((item) => ({
          label: item.name,
          value: item.code,
          isLeaf: props.regionType === type,
          type,
        }));
      }
      if (props.regionCodes) {
        res = res.filter((item) => {
          return (
            props.regionCodes.indexOf(item.value) > -1 ||
            props.regionCodes.indexOf(Number(item.value)) > -1
          );
        });
      }
      res.unshift(defaultAllRegionMap[type]);
      return res;
    },
    [props.regionCodes],
  );
  useEffect(() => {
    if (props.regionType) {
      const provinceOptions = FormatOption(Region.getProvinces(), 'province');
      setRegionOptions(provinceOptions);
    }
  }, [FormatOption]);

  useEffect(() => {
    setValue(props.value);

    if (props.value && props.regionType) {
      setValue(props.value?.map((code) => String(code)));
      const typeMap = {
        0: 'province',
        1: 'city',
        2: 'country',
      };
      let children = [];
      let provinceCode = '';
      props.value.forEach((code, i) => {
        if (i < props.value.length - 1) {
          if (i === 1) {
            const child = FormatOption(
              regionLoop[typeMap[i]].getFn?.(String(code)),
              regionLoop[typeMap[i]]?.type,
              { value: String(code) },
            );
            children = children.map((item) => {
              if (item.value == code) {
                return {
                  ...item,
                  children: child,
                };
              }
              return item;
            });
            setRegionOptions((pre) => {
              return pre.map((item) => {
                if (item.value == provinceCode) {
                  return {
                    ...item,
                    children,
                  };
                }
                return item;
              });
            });
          }
          if (i === 0) {
            children = FormatOption(
              regionLoop[typeMap[i]].getFn?.(String(code)),
              regionLoop[typeMap[i]]?.type,
              { value: String(code) },
            );
            provinceCode = String(code);

            setRegionOptions((pre) => {
              return pre.map((item) => {
                if (item.value == code) {
                  return {
                    ...item,
                    children,
                  };
                }
                return item;
              });
            });
          }
        }
      });
    }
  }, [props.value]);

  // 为了与 antd 的生态保持兼容性，我们要求必须要使用 `.@{ant-prefix}` 变量来生成类名
  const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
  const prefixCls = getPrefixCls('btri-cascader');

  const { dropdownMenuColumnStyle, showSearch = false, multiple } = props;

  const [_dropdownVisible, _setDropdownVisible] = useState(false);

  const _onDropdownVisibleChange = new AOP<boolean, void>(
    props.onDropdownVisibleChange,
  )
    .before((v) => {
      _setDropdownVisible(v);
    })
    .getFunction();

  const _onLoadData = new AOP<Option[], void>(props.loadData)
    .before((selectedOptions) => {
      if (props.regionType) {
        const targetOption = selectedOptions[selectedOptions.length - 1];
        targetOption.children = FormatOption(
          regionLoop[(targetOption as any).type].getFn?.(targetOption.value),
          regionLoop[(targetOption as any).type]?.type,
          targetOption,
        );
        setRegionOptions((pre) => [...pre]);
      }
    })
    .getFunction();

  const _onChange = new AOP<any[], void>(props.onChange)
    .before((res) => {
      setValue([...new Set(res)]);
    })
    .getFunction();

  const _suffixIcon = useMemo(() => {
    if (props.suffixIcon) {
      return props.suffixIcon;
    }
    const icons = {
      search: (
        <Icon
          iconName="Search"
          style={{
            fontSize: '16px',
            color: _dropdownVisible && 'var(--primary-6)',
          }}
        ></Icon>
      ),
      direction: (
        <Icon
          iconName="Down"
          style={{
            fontSize: '16px',
            color: _dropdownVisible
              ? 'var(--primary-6)'
              : 'var(--caption-font)',
            transform: _dropdownVisible && 'rotate(180deg)',
          }}
        ></Icon>
      ),
    };

    return icons[showSearch ? 'search' : 'direction'];
  }, [_dropdownVisible, showSearch]);

  const _dropdownMenuColumnStyle = useMemo(() => {
    return {
      padding: '5px 12px',
      ...dropdownMenuColumnStyle,
    };
  }, [dropdownMenuColumnStyle]);

  return (
    <div className={classNames(`${prefixCls}-container`, { multiple })}>
      <AntdCascader
        showSearch={false}
        allowClear
        placeholder={translate(
          'packages.base.src.Cascader.index.请选择',
          locale?.locale,
        )}
        displayRender={
          props.showCheckedStrategy === 'SHOW_CHILD' &&
          ((label) => {
            return label.pop();
          })
        }
        changeOnSelect={props.regionType ? true : false}
        {...props}
        className={classNames(`${prefixCls}-box`, props.className)}
        onDropdownVisibleChange={_onDropdownVisibleChange}
        suffixIcon={_suffixIcon}
        style={{ width: '100%', ...props.style }}
        dropdownClassName={classNames(
          `${prefixCls}-dropdown`,
          props.dropdownClassName,
        )}
        dropdownMenuColumnStyle={_dropdownMenuColumnStyle}
        options={props.regionType ? regionOptions : props.options}
        loadData={_onLoadData}
        value={_value}
        onChange={_onChange}
      >
        {props.children}
      </AntdCascader>
      {multiple && (
        <Icon
          iconName={_dropdownVisible ? 'Up' : 'Down'}
          className={classNames(`${prefixCls}-direction-icon`, {
            active: _dropdownVisible,
          })}
        ></Icon>
      )}
    </div>
  );
};

Cascader.SHOW_CHILD = AntdCascader.SHOW_CHILD;
Cascader.SHOW_PARENT = AntdCascader.SHOW_PARENT;

export { Cascader };
