import {ReactElement, useEffect, useMemo, useRef} from 'react';
import {
  FilterButtonGroup,
  FilterDatePicker,
  FilterField,
  FilterFieldWrapper,
  FilterKeySelect,
  FilterSelect,
  RangeValue,
} from '@components';
import {DictionaryParamsType} from '@models';
import {Dayjs} from 'dayjs';

import {differenceBy} from 'lodash-es';
import {useLatest} from 'ahooks';
import {Card} from 'antd';

export type MapValue<S extends Record<string, string | string[]>> =
  | {label: string; type: 'field' | 'date'; value: keyof S}
  | {
      label: string;
      type: 'keySelect';
      selectKey: DictionaryParamsType;
      value: keyof S;
    }
  | {
      label: string;
      type: 'select';
      value: keyof S;
      options: {label: string; value: string}[];
      multiple?: boolean;
      hideClear?: boolean;
    };

export type FilterGroupMap<S extends Record<string, string | string[]>> = Map<
  string,
  MapValue<S>
>;

type Props<S extends Record<string, string | string[]>> = {
  filterData: string;
  sourceMap: FilterGroupMap<S>;
  fixedMap: MapValue<S>[];
  fields: Record<string, string | string[]>;
  isSearching: boolean;
  dates?: RangeValue<Dayjs>;
  onReset: () => void;
  onSearch: () => void;
  onFilter?: () => void;
  onChange?: (key: any) => (value: string | number) => void;
  onDatesChange?: (dates: RangeValue<Dayjs>) => void;
  testId: string;
};

function FilterTool<S extends Record<string, string | string[]>>({
  onChange,
  fields,
  dates,
  onDatesChange,
  fixedMap,
  onSearch,
  filterData,
  sourceMap,
  onFilter,
  onReset,
  isSearching,
  testId,
}: Props<S>): ReactElement {
  const prevEls = useRef<MapValue<S>[]>([]);

  const list = useMemo<MapValue<S>[]>(
    function () {
      const arr = filterData.split(',').filter(Boolean);

      const els = arr
        .map(function (id) {
          if (!sourceMap.has(id)) return;
          return {...sourceMap.get(id)!, id: Number(id)};
        })
        .filter(Boolean)
        .sort((a, b) => a.id - b.id);

      const nextEls = [...fixedMap, ...els];

      return nextEls;
    },
    [filterData, fixedMap, sourceMap],
  );

  // onSearch可能会变更
  const onSearchFn = useLatest(onSearch);

  useEffect(
    function () {
      /**
       * 新元素如果有缺少的需要将缺少的内容初始化数据
       *
       * [用户名称， 角色名称， 手机号]
       *
       * [用户名称，角色名称， 电话， 邮箱]
       *
       * 以上情况需要充值手机号的值并且触发查询
       *
       * [用户名称， 角色名称]
       *
       * [用户名称，角色名称， 电话， 邮箱]
       *
       * 以上情况不触重置查询
       */
      const diffEls = differenceBy(prevEls.current, list, 'id');

      prevEls.current = list;

      if (diffEls.length) {
        diffEls.forEach(function ({value, type}) {
          if (type === 'date') {
            onDatesChange?.([null, null]);
          } else {
            onChange?.(value)('');
          }
        });

        // 确保第二次查询时的搜索数据时最新的可以触发搜索
        setTimeout(function () {
          onSearchFn.current();
        }, 0);
      }
    },
    [list, onChange, onDatesChange, onSearchFn],
  );

  return (
    <Card>
      <FilterFieldWrapper onSearch={onSearch} testId={testId}>
        {list.map(function (state) {
          switch (state.type) {
            default:
            case 'field': {
              return (
                <FilterField
                  key={state.label}
                  name={state.value as string}
                  label={state.label}
                  value={fields[state.value as string] as string}
                  onChange={onChange?.(state.value)}
                />
              );
            }
            case 'date': {
              return (
                <FilterDatePicker
                  key={state.label}
                  name={state.value as string}
                  label={state.label}
                  value={dates!}
                  onChange={onDatesChange!}
                />
              );
            }
            case 'keySelect': {
              return (
                <FilterKeySelect
                  key={state.label}
                  selectKey={state.selectKey}
                  name={state.value as string}
                  label={state.label}
                  value={fields[state.value as string] as string}
                  onChange={onChange?.(state.value as string)}
                />
              );
            }
            case 'select': {
              return (
                <FilterSelect
                  key={state.label}
                  name={state.value as string}
                  label={state.label}
                  value={fields[state.value as string]}
                  onChange={onChange?.(state.value)}
                  options={state.options}
                  hideClear={state.hideClear}
                  multiple={state.multiple}
                />
              );
            }
          }
        })}
        <FilterButtonGroup
          onSearch={onSearch}
          isSearching={isSearching}
          onReset={onReset}
          onFilter={onFilter}
        />
      </FilterFieldWrapper>
    </Card>
  );
}

export default FilterTool;
