import {
  getAllMaterialList,
  getAllRoleList,
  getAllStorage,
  getAllUser,
  getDictionaryOptions,
} from '@apis';
import {
  BaseResult,
  DictionaryData,
  DictionaryParamsType,
  StorageListData,
} from '@models';
import {useQuery} from '@tanstack/react-query';
import {useLatest} from 'ahooks';
import {useEffect, useMemo, useRef, useState} from 'react';
import {debounce} from 'lodash-es';

type Options<T extends {id: number | string}, P extends unknown[]> = {
  fn: (...args: P) => BaseResult<T[]>;
  findName: (state: T) => string;
  addAll: boolean;
  findValue?: (state: T) => string;
  params: P;
};

function useQueryOptions<T extends {id: number | string}, P extends unknown[]>(
  options: Options<T, P>,
) {
  const {findValue, fn, findName, addAll, params} = options;

  const findValueFn = useLatest(findValue);

  return useQuery({
    queryKey: [fn.name, addAll, findValueFn, ...Object.values(params)],
    async queryFn({signal}) {
      const newParams = [...params, signal] as unknown as P;

      const data = await fn(...newParams);

      if (data.msg === '200') {
        const list = data.data.map(function (value) {
          return {
            label: findName(value),
            value: findValueFn.current
              ? findValueFn.current?.(value)
              : String(value.id),
          };
        });

        if (addAll) list.unshift({label: '全部', value: ''});

        return list;
      }

      return [];
    },
    initialData: [],
    cacheTime: 1000 * 60 * 10,
    // 兼容useStorageOptions 当id不传入的时候返回空数组
    // 确保与仓库id联动
    enabled: params.length > 0 ? Boolean(params[0]) : true,
  });
}

export function useStorageOptions(
  addAll = false,
  findValue?: (state: StorageListData) => string,
  options?: {id: string; clear: () => void},
) {
  const prevId = useRef(options?.id);

  useEffect(
    function () {
      // 如果之前为空 说明是第一次进入 此时不清除
      if (!prevId.current) {
        prevId.current = options?.id;
        return;
      }

      if (prevId.current !== options?.id) {
        prevId.current = options?.id;
        options?.clear();
      }
    },
    [options],
  );

  return useQueryOptions({
    fn: getAllStorage,
    findName: state => state.storageLocationName,
    addAll,
    findValue,
    params: [options?.id ?? ''],
  });
}

export function useRoleOptions(addAll = false) {
  return useQueryOptions({
    fn: getAllRoleList,
    findName: state => state.roleName,
    addAll,
    params: [],
  });
}

/**
 * 查询内容较少时使用，例如仓库
 * 本地可以做校验 不需要频繁请求服务器
 */
export function useDictionaryOptions(
  type: DictionaryParamsType,
  addAll = false,
  findValue: (state: DictionaryData) => string = state => state.tldId,
) {
  return useQuery({
    queryKey: [getDictionaryOptions.name, type, addAll],
    async queryFn({signal}) {
      const data = await getDictionaryOptions(type, '', signal);

      if (data.msg === '200') {
        const list = data.data.map(function (value) {
          return {
            label: value.name,
            value: findValue(value),
            type: value.warehouseType,
          };
        });

        if (addAll) list.unshift({label: '全部', value: '', type: ''});

        return list;
      }

      return [];
    },
    initialData: [],
    cacheTime: 1000 * 60 * 10,
  });
}

/** filterSelect使用 */
export function useDictionaryKeyOptions(
  type: DictionaryParamsType,
  findValue: (state: DictionaryData) => string = state => state.tldId,
  options: {
    lazy?: boolean;
    search?: string;
  } = {},
) {
  const {lazy, search} = options;
  // lazy模式下 当search变动时触发重新查询
  let searchName = '';
  const enabledLazy = lazy && search !== void 0;
  if (enabledLazy) {
    searchName = search;
  }

  const {data, isFetching} = useQuery({
    queryKey: [getDictionaryOptions.name, type, searchName],
    async queryFn({signal}) {
      const data = await getDictionaryOptions(type, searchName, signal);

      if (data.msg === '200') {
        const list = data.data.map(function (value) {
          return {
            label: value.name,
            value: findValue(value),
            type: value.warehouseType,
          };
        });

        return list;
      }

      return [];
    },
    initialData: [],
    cacheTime: 1000 * 60 * 10,
    enabled: enabledLazy ? Boolean(searchName) : true,
  });

  return {options: data, isFetching};
}

export function useUserOptions(addAll = false) {
  const {data} = useQuery({
    queryKey: [getAllUser.name, addAll],
    async queryFn({signal}) {
      const data = await getAllUser(signal);

      if (data.msg === '200') {
        const list = data.data.map(function (value) {
          return {label: value.realName, value: String(value.id)};
        });

        if (addAll) list.unshift({label: '全部', value: ''});

        return list;
      }

      return [];
    },
    initialData: [],
    cacheTime: 1000 * 60 * 10,
  });

  return data;
}

/**
 * 数量较多的时候用，第一次查询可能会很慢
 * 例如物料和供应商
 */
export function useDictionaryWidthCode(
  type: DictionaryParamsType,
  {
    addAll = false,
    findValue = state => state.tldId,
    enabled = false,
  }: {
    addAll?: boolean;
    findValue?: (state: DictionaryData) => string;
    enabled?: boolean;
  } = {},
) {
  const [code, setCode] = useState('');

  const {data, isFetching} = useQuery({
    queryKey: [
      getDictionaryOptions.name,
      type,
      addAll,
      'useDictionaryWidthCode',
      code,
    ],
    async queryFn({signal}) {
      const data = await getDictionaryOptions(type, code, signal);
      if (data.msg === '200') {
        const list = data.data.map(function (value) {
          return {
            label: value.name,
            value: findValue(value),
            type: value.warehouseType,
          };
        });
        if (addAll) list.unshift({label: '全部', value: '', type: ''});
        return list;
      }
      return [];
    },
    initialData: [],
    cacheTime: 1000 * 60 * 10,
    enabled: Boolean(code) || enabled,
  });

  const onSearch = useMemo(function () {
    function onSearchValue(value: string) {
      setCode(value);
    }

    return debounce(onSearchValue, 500, {leading: false, trailing: true});
  }, []);

  return [{data, isFetching}, onSearch] as const;
}

export function useMaterialOptions() {
  const {data, isFetching} = useQuery({
    queryKey: [getAllMaterialList.name],
    async queryFn({signal}) {
      const data = await getAllMaterialList(
        {partType: '半成品', nameOrCode: ''},
        signal,
      );

      if (data.msg === '200')
        return data.data.map(val => ({label: val.name, value: val.code}));

      return [];
    },
    initialData: [],
  });

  return {data, isFetching};
}
