import React, { useState, useEffect } from 'react';
import { Select, Divider, Button, Tooltip } from 'antd';
import { YSelectProps, YSelectCustomValue } from './select.interface';
import {
  DEFAULT_CONFIG,
  DEFAULT_ORIGIN_CONFIG,
  QUERY_ORIGIN_CONFIG,
  ADD_ORIGIN_CONFIG,
  ADD_CUSTOM_CONFIG,
} from './select.config';
import { AddBtnStyle, SelectStyle, IconWrapStyle, OptionStyle } from './styles';
import { YIcon } from '../icon';
import { SelectValue } from 'antd/lib/select';
import {YPopover} from '../popover/index'
// import '../styles/global.less';

export const YSelect: React.FC<YSelectProps<any>> = ({
  onChange,
  ...props
}) => {
  const [loading, setLoading] = useState(false);
  
  let timeout = 0;
  const debounce = (func: () => void) => {
    clearTimeout(timeout);
    if(typeof window !== 'undefined'){
      timeout = window.setTimeout(function () {
        clearTimeout(timeout);
        func()
      }, requestTime)
    }
  }

  const _beforeOriginProps = {
    ...DEFAULT_ORIGIN_CONFIG,
    ...props.originalProps,
  } as any;
  const { options, ..._originalProps } = _beforeOriginProps;
  const _props = { ...DEFAULT_CONFIG, ...props };
  // 可搜索
  if (_originalProps.showSearch) {
    Object.assign(_originalProps, {
      ...QUERY_ORIGIN_CONFIG,
      ..._originalProps,
      onSearch: (text: string) => debounce(() => handleSearch(text)),
    });
  }
  // 可自增项
  if (props.showAddBtn) {
    Object.assign(_originalProps, {
      ...ADD_ORIGIN_CONFIG,
      ..._originalProps,
    });
    Object.assign(_props, {
      ...ADD_CUSTOM_CONFIG,
      ..._originalProps,
    });
  }

  const { 
    value, 
    shouldInitFetch,
    shouldFetchWhenEmpty,
    request,
    requestTime,
    valueType,
    addBtnText,
    showAddBtn,
    previewPlaceholder,
    disabled,
    showDefaultOption,
    defaultOptionValue,
    defaultOptionText,
    hoverText,
    hoverTextConfig,
    shouldRequestOnFilter,
   } = _props;
   const { dropdownRender } = _originalProps

  const valueTypeIsObject = valueType === 'object';
  const [dataSource, setDataSource] = useState<YSelectCustomValue[]>(
    (options as YSelectCustomValue[]) || [],
  );
  const [initStatus, setInitStatus] = useState(true);
  const [keyword, setKeyword] = useState<string | undefined>(undefined);
  const [isAddNewItem, setIsAddNewItem] = useState(false);

  // 远程获取下拉项时，进入表单默认选中项
  useEffect(() => {
    doInitFetch()
  }, [shouldInitFetch]);

  useEffect(() => {
    if (props.originalProps && props.originalProps.options && JSON.stringify(props.originalProps.options) !== JSON.stringify(dataSource)) {
      setDataSource(props.originalProps?.options as YSelectCustomValue[] || [])
    }
  }, [props.originalProps])

  // 默认搜索
  const doInitFetch = () => {
    if (!shouldInitFetch) return
    let _defaultKeyword = value ? value : undefined
    if (_defaultKeyword) {
      _defaultKeyword = valueTypeIsObject ? (value ? value.label : undefined) : value
    }
    debounce(() => handleSearch(_defaultKeyword, true))
  }

  // 搜索
  const  handleSearch = async (inputText: string, isFromInit?: boolean) => {
    if (!shouldFetchWhenEmpty) {
      if (!isFromInit && (inputText === undefined || inputText === '')) return;
    }
    // 只过滤时不请求
    if (!shouldRequestOnFilter && _originalProps.filterOption && !isFromInit) return;
    setLoading(true);
    setKeyword(inputText);
    const res = await handleRequest(inputText) || [];
    setDataFromApiData(res, isFromInit)
    setLoading(false);
    setInitStatus(false);
    setIsAddNewItem(false);
  }

  const handleRequest = async (inputText: string) => {
    try {
      return request && typeof request === 'function' && (await request(inputText)) || options;
    } catch(e) {
      return []
    }
  }

  // 获取接口数据结果
  const setDataFromApiData = (responseData: any, isFromInit?: boolean) => {
    const { apiDataKey, apiLabelKey, apiValueKey, handleResponseData } = _props;
    let _list = responseData;
    let resultList = []
    if (apiDataKey) _list = responseData[apiDataKey]
    
    if (apiLabelKey && apiValueKey) {
      resultList = (_list && _list.length && _list || []).map((el: any) => ({
        data: el,
        label: el[apiLabelKey],
        value: el[apiValueKey],
      }))
    }
    if (handleResponseData) {
      resultList = handleResponseData(_list) as YSelectCustomValue[];
    }
    // 远程搜索时没有匹配的数据，默认加上该项
    if (isFromInit && valueTypeIsObject) {
      let initOptions = []
        // 多选时，加上默认值的项
        if (Array.isArray(value)) {
          initOptions = value
        }
      if (value && value.value && value.label) {
        const hasCurOption = resultList.find((item: YSelectCustomValue) => item.value === value && item.label === value.label)
        if (!hasCurOption) {
          initOptions.push({
            data: {},
            label: value.label,
            value: value.value,
          })
        }
      }
      resultList.unshift(...initOptions)
    }
    setDS(resultList);
  }

  // 新增项
  const addItem = () => {
    if (isAddNewItem || !keyword?.trim()) return;
    setIsAddNewItem(true);
    setDS([{ value: '', label: keyword, data: {} }, ...dataSource]);
  };


  // 处理项数据
  // 为了避免值类型为对象时，label和value的顺序引发的无法匹配数据问题
  const setDS = (list: YSelectCustomValue[]) => {
    const newList = (list || []).map((item) => {
      const { value, label, ...rest } = item;
      return {
        value: item.value,
        label: item.label,
        ...rest,
      };
    });
    setDataSource(newList);
  };

  // 额外下拉项
  const expandRender = (menu: React.ReactElement) => {
    const defaultMenu = (
      <>
        {loading && (
          <IconWrapStyle>
            <YIcon name="LoadingOutlined" />
          </IconWrapStyle>
        )}
        {menu}
      </>
    );
    const defaultAddBtn = (
      <>
        {defaultMenu}
        <Divider style={{ margin: 0 }} />
        <AddBtnStyle onClick={addItem}>
          <Button type="link">
            <YIcon name="PlusOutlined" />
            {addBtnText}
          </Button>
        </AddBtnStyle>
      </>
    );
    if (showAddBtn) {
      if (
        dropdownRender &&
        typeof dropdownRender === 'function'
      ) {
        return (
          <>
            {defaultMenu}
            {dropdownRender(defaultMenu)}
          </>
        );
      }
      return defaultAddBtn;
    } else {
      return defaultMenu;
    }
  };

  // 获取当前值的label
  const getCurLabel = () => {
    let labelText = ''
    if (options) {
      const curValueItem = options?.find((el: { [x: string]: any }) => el.value === value) || {};
      labelText = curValueItem.label;
    }
    if (valueTypeIsObject) {
      labelText = _props.value?.label;
    }
    if (!labelText) labelText = previewPlaceholder || '' ;
    return labelText;
  }

  // 获取值
  const getValue = () => {
    let _val = value;
    if (valueTypeIsObject && _val) {
      if (Array.isArray(_val)) { // 多选时
        return _val.map(el => stringifyJson(el))
      } else {
        const getActivyOption = dataSource.find(item => {
          if (item.value === value.value && item.label === value.label) {
            return item;
          }
        }) || {}
        _val = stringifyJson(getActivyOption);
      }
    }
    return _val;
  }

  // 获取hover内容
  const getOptionText = (item: YSelectCustomValue) => {
    if (hoverText) {
      let content: string | React.ReactNode | null | undefined = item.label;
      if (typeof hoverText === 'function') content = hoverText(item)
      return (
      <YPopover 
        type='tips'
        content={content}
        {...hoverTextConfig}
        >
        {item.label}
      </YPopover>
      )
    } else {
      return item.label
    }
  }


  if (_props.disabled) {
    return <span>{getCurLabel()}</span>
  }
  

  return (
    <SelectStyle
      {..._originalProps}
      minwidth={_props.minWidth}
      value={getValue()}
      dropdownRender={expandRender}
      filterOption={(val: string, option: any) => {
        const { filterOption } = _originalProps
        if (!filterOption) return true;
        if (typeof filterOption === 'function') return filterOption(val, option)
        return option.children.toLowerCase().includes(val.toLowerCase())
      }}
      onChange={(value: SelectValue, opt: any) => {
        onChange &&
        onChange(valueTypeIsObject ? parseJson(value as string) : value, opt)
      }}
    >
      {showDefaultOption && (
        <OptionStyle value={defaultOptionValue === undefined ? '' : defaultOptionValue}>{defaultOptionText}</OptionStyle>
      )}
      {(dataSource || []).map((item, index: number) => (
        <OptionStyle
          key={valueTypeIsObject ? `${JSON.stringify(item)}_${index}` : `${item.value}_${index}`}
          value={valueTypeIsObject ? JSON.stringify(item) : item.value}
          disabled={item.disabled || false}
          data={item.data || {}}
        >
          {getOptionText(item)}
        </OptionStyle>
      ))}
    </SelectStyle>
  );
};


const parseJson = (jsonStr: string | number | string[] | number[]) => {
  try {
    if (Array.isArray(jsonStr)) {
      const result: {}[] = [];
      (jsonStr || []).forEach((el: string | number) => result.push(parseJson(el)))
      return result;
    }
    return JSON.parse(`${jsonStr}`)
  } catch(e) {
    return {}
  }
}

const stringifyJson = (data: object | string) => {
  if (data === '' || JSON.stringify(data) === '{}') return undefined
  try {
    return JSON.stringify(data)
  } catch(e) {
    return undefined
  }
}
