import React, {
  forwardRef,
  ForwardRefRenderFunction,
  Fragment,
  useCallback,
  useContext,
  useMemo,
  useRef,
  useState,
  useImperativeHandle,
} from 'react';
import classNames from 'classnames';
import View from '@alifd/meet-react/es/view';
import { ItemContext } from '@alifd/meet-react/es/form';
import BottomButton from '@alifd/meet-react/es/bottom-button';
import SelectDrawer, { LocaleType as SelectDrawerLocalType } from '@alifd/meet-react/es/select-drawer';
import { useLocale } from '@alifd/meet-react/es/locale';
import defaultLang from '@alifd/meet-react/es/locale/lang/zh-cn';
import { useValue } from '@alifd/meet-react/es/utils/hooks';
import { findInArray, getDataSource, isFunction, isString, isValidArray } from '@alifd/meet-react/es/utils';
// import SelectBody from '@alifd/meet-react/es/select/section/select-body';
import SelectSearch from '@alifd/meet-react/es/select/section/select-search';
import SelectedListDrawer from '@alifd/meet-react/es/select/section/selected-list-drawer';
import {
  defaultLocalFilter,
  getValidEvtValues,
  innerRenderSelection,
  isEqualItems,
} from '@alifd/meet-react/es/select/util';
import SelectContext from '@alifd/meet-react/es/select/context';
import { LocaleType } from '@alifd/meet-react/es/select/types';
import { ExtraSelectProps } from './type';

const BaseSelect: ForwardRefRenderFunction<any, ExtraSelectProps> = (props, ref) => {
  const {
    prefix = 'mt-',
    placeholder,
    value: _value,
    type = 'normal',
    defaultValue,
    className,
    mode = 'single',
    hasSearch,
    children,
    dataSource: _dataSource,
    disabled = false,
    hasClear,
    onSearch,
    displayType = 'normal',
    filterLocal = true,
    filter = defaultLocalFilter,
    renderSelection,
    useDetailValue,
    onChange = () => {},
    onClear = () => {},
    onCancel = () => {},
    onOk = () => {},
    locale: _locale,
    size: sizeProp,
    notFoundContent = '',
    popupContent, // 自定义弹窗内容
    ...others
  } = props;

  const { isInsideForm, size: contextSize } = useContext(ItemContext);
  const size = sizeProp || (isInsideForm ? contextSize : 'medium');
  const [searchVal, setSearchVal] = useState('');
  const selectLocale = useLocale<LocaleType>('Select', props, defaultLang.Select);
  const selectDrawerLocal = useLocale<SelectDrawerLocalType>('SelectDrawer', {}, defaultLang.SelectDrawer);
  const clsPrefix = `${prefix}select`;

  const baseSelectRef = useRef(null);

  const dataSource = useMemo(() => {
    return getDataSource(props.dataSource, props.children);
  }, [props.dataSource, props.children]);

  const fitValue = (v: any) => {
    if (v === '' || v === null) {
      return [];
    }

    const x = Array.isArray(v) ? v : [v];

    if (useDetailValue) {
      return x;
    } else if (isValidArray(x)) {
      return x.map((item) => {
        const tmp = findInArray(dataSource, (d: any) => d.value === item);
        return (
          tmp || {
            label: item,
            value: item,
          }
        );
      });
    } else {
      return [];
    }
  };

  const compare = (a: any, b: any) => isEqualItems(a, b, true);

  const [value, setValue, isControlled] = useValue(props, [], {
    fitValue,
    compare,
  });
  const [innerValue, setInnerValue] = useState(value);
  const [confirmVisible, setConfirmVisible] = useState(false);
  const isSingle = mode === 'single';
  const searchRef = useRef(null);
  const realHasSearch = props.hasSearch || props.showSearch;

  useMemo(() => {
    if (isControlled && !compare(value, innerValue)) {
      setInnerValue(value);
    }
  }, [value]);

  const handleCancel = useCallback(
    (reason) => {
      setInnerValue(value);
      if (searchRef && searchRef.current) {
        searchRef.current.setValue('');
      }
      if (baseSelectRef && baseSelectRef.current) {
        baseSelectRef.current.hide();
      }
      if (isFunction(onCancel)) {
        onCancel(reason);
      }
    },
    [value],
  );

  const handleOk = () => {
    if (!isControlled) {
      setValue(innerValue);
    }

    // 判断前后两次选择是否有差异
    const changed = !isEqualItems(value, innerValue);

    if (isFunction(onOk)) {
      onOk();
    }

    if (changed && isFunction(onChange)) {
      const { value: val, items } = getValidEvtValues({
        selectedItems: innerValue,
        isSingle,
        useDetailValue,
      });

      onChange(val, 'change', items);
    }

    if (searchRef && searchRef.current) {
      searchRef.current.setValue('');
    }
    if (baseSelectRef && baseSelectRef.current) {
      baseSelectRef.current.hide();
    }
  };

  const handleTotalClick = () => {
    setConfirmVisible(true);
  };

  const handleClear = () => {
    if (!isControlled) {
      setValue([]);
      setInnerValue([]);
      if (searchRef && searchRef.current) {
        searchRef.current.setValue('');
      }
    }

    if (isFunction(onClear)) {
      onClear();
    }

    if (isFunction(onChange)) {
      const { value: val, items } = getValidEvtValues({
        selectedItems: [],
        useDetailValue,
        isSingle,
      });
      onChange(val, 'clear', items);
    }
  };

  const handleConfirmDone = (items: any[]) => {
    setInnerValue(items);
    setConfirmVisible(false);
  };

  const handleConfirmCancel = () => {
    setConfirmVisible(false);
  };

  const contextValue = useMemo(() => {
    return {
      ...props,
      hasSearch: realHasSearch,
      dataSource,
      type,
      mode,
      size,
      prefix,
      value,
      innerValue,
      displayType,
      locale: selectLocale,
      onChange: (v: any) => setInnerValue(v),
      searchValue: searchVal,
      setSearchValue: setSearchVal,
    };
  }, [
    props,
    realHasSearch,
    dataSource,
    type,
    mode,
    size,
    prefix,
    value,
    innerValue,
    displayType,
    selectLocale,
    searchVal,
  ]);

  useImperativeHandle(ref, () => Object.assign(baseSelectRef.current));

  return (
    <Fragment>
      <SelectDrawer
        {...others}
        size={size}
        ref={baseSelectRef}
        // showToolbar={!realHasSearch}
        showToolbar={false}
        type={type}
        disabled={disabled}
        placeholder={placeholder}
        hasClear={hasClear}
        className={classNames(clsPrefix, className)}
        content={renderSelection ? renderSelection(value) : innerRenderSelection(value, contextValue)}
        onClear={handleClear}
        onCancel={handleCancel}
        onOk={handleOk}
        // @ts-ignore
        drawerClassName={classNames({
          [`${clsPrefix}--searchable`]: realHasSearch,
        })}
      >
        <SelectContext.Provider value={contextValue}>
          <Fragment>
            {realHasSearch && <SelectSearch ref={searchRef} />}

            {/* {dataSource.length === 0 && !realHasSearch ? (
              // 因 Provider 导致 select-drawer 空选项判断失败
              <View className={`${clsPrefix}-drawer-content ${clsPrefix}drawer-drawer--empty`}>
                {isString(notFoundContent) ? (
                  <div className={`${clsPrefix}drawer-drawer-empty-text`}>{notFoundContent}</div>
                ) : (
                  <View className={`${clsPrefix}drawer-drawer-empty-text`}>{notFoundContent}</View>
                )}
              </View>
            ) : (
              <View className={`${clsPrefix}-option-list`}>
                <SelectBody />
              </View>
            )} */}

            {popupContent}

            {realHasSearch && (
              <View className={`${clsPrefix}-drawer-footer`}>
                <BottomButton
                  enableSafeArea
                  okText={selectDrawerLocal.ok}
                  cancelText={selectDrawerLocal.cancel}
                  onOk={handleOk}
                  onCancel={() => handleCancel('cancel-button')}
                >
                  {!isSingle && (
                    <View className={`${clsPrefix}-footer-counter`} onClick={handleTotalClick}>
                      <span>{selectLocale.totalPrefixText}</span>
                      <span className={`${clsPrefix}-total-num`}>{innerValue.length}</span>
                      <span>{selectLocale.totalSuffixText}</span>
                    </View>
                  )}
                </BottomButton>
              </View>
            )}
          </Fragment>
        </SelectContext.Provider>
      </SelectDrawer>
      {!isSingle && (
        <SelectedListDrawer
          prefix={contextValue.prefix}
          innerValue={contextValue.innerValue}
          locale={contextValue.locale}
          visible={confirmVisible}
          onOk={handleConfirmDone}
          onCancel={handleConfirmCancel}
        />
      )}
    </Fragment>
  );
};

BaseSelect.displayName = 'SelectDrawer';

export default forwardRef(BaseSelect);
