import { StarFilled, StarOutlined } from '@ant-design/icons';
import isEqual from 'lodash/isEqual';
import React, { Dispatch, SetStateAction, useCallback, useContext, useMemo, useState } from 'react';
import useMedia from 'react-use/lib/useMedia';
import Button from '../../../button';
import ConfigProvider from '../../../config-provider';
import Form from '../../../form';
import Input from '../../../input';
import Popover from '../../../popover';
import Tag from '../../../tag';

import {
  ApolloColumnType,
  SelectedView,
  OrderDirection,
  Ordering,
  SelectedViewsProps,
} from '../../interfaces';
import { findColumn } from '../../utils/findColumn';
import { generateLabel } from '../../utils/generateLabel';
import defaultLocale from '../../../locale/en_US';
import { localFilterToComponent } from '../../utils/localFilterToComponent';
import Modal from '../../../modal';

interface SelectedViewButtonProps<T> {
  columns: ApolloColumnType<T>[];
  selectedViews: SelectedViewsProps;
  activeKey: string;
  value: SelectedView[];
  queryValue: string;
  sortValue: string;
  filterValues: Record<string, any>;
  defaultSortValue?: Ordering;
  allSelectedViews: SelectedView[];
  searchParams: Record<string, any>;
  setQueryValue: Dispatch<SetStateAction<string>>;
  setSortValue: Dispatch<SetStateAction<string>>;
  setFilterValues: Dispatch<SetStateAction<Record<string, any>>>;
  setSearchParams: (nextQuery: Record<string, any>) => void;
  onChange: React.Dispatch<React.SetStateAction<SelectedView[]>>;
  onActiveKeyChange: Dispatch<SetStateAction<string>>;
}

export const SelectedViewButton = <T extends {}>({
  defaultSortValue,
  selectedViews,
  columns,
  activeKey,
  queryValue,
  sortValue,
  filterValues,
  value,
  searchParams,
  setQueryValue,
  setSortValue,
  setFilterValues,
  setSearchParams,
  allSelectedViews: propsAllSelectedViews,
  onChange,
  onActiveKeyChange,
}: SelectedViewButtonProps<T>) => {
  const [form] = Form.useForm();
  const [loading, setLoading] = useState(false);
  const {
    getPrefixCls,
    locale: { ApolloTable: locale } = { ApolloTable: defaultLocale.ApolloTable },
  } = useContext(ConfigProvider.ConfigContext);
  const [visible, setVisible] = useState(false);

  const showSelectedViewButton = useMedia('(max-width: 892px)');

  const allSelectedViews = useMemo(
    () => propsAllSelectedViews.filter(item => item.id !== 'all'),
    [propsAllSelectedViews],
  );

  const disabled = useMemo(() => {
    // 如果是 local 或 服务端，永远是 false
    if (activeKey.startsWith('savedSearch') || searchParams.saved_search_id) {
      return false;
    }

    // 如果是所有，不对比排序
    if (activeKey === 'all') {
      if (
        queryValue ||
        Object.keys(filterValues).length > 0 ||
        sortValue !==
          (defaultSortValue ? `${defaultSortValue.field} ${defaultSortValue.direction}` : '')
      ) {
        return false;
      }
      return true;
    }

    // 否则是配置的
    const current = allSelectedViews?.find(item => item.id === activeKey);

    // 如果条件相等禁用
    if (
      queryValue === (current?.query || '') &&
      sortValue ===
        (current?.orderBy ? `${current.orderBy.field} ${current.orderBy.direction}` : '') &&
      isEqual(filterValues, current?.filters || {})
    ) {
      return true;
    }
    return false;
  }, [
    activeKey,
    searchParams.saved_search_id,
    allSelectedViews,
    queryValue,
    sortValue,
    filterValues,
    defaultSortValue,
  ]);

  const isEdit = useMemo(() => {
    if (activeKey.startsWith('savedSearch')) {
      const current = allSelectedViews.find(item => item.id === activeKey);
      if (
        current &&
        queryValue === (current.query || '') &&
        sortValue ===
          (current.orderBy ? `${current.orderBy.field} ${current.orderBy.direction}` : '') &&
        isEqual(filterValues, localFilterToComponent(current.filters || {}, columns))
      ) {
        return true;
      }
      return false;
    }
    if (disabled || searchParams.saved_search_id) {
      return true;
    }

    return false;
  }, [
    activeKey,
    disabled,
    searchParams.saved_search_id,
    allSelectedViews,
    queryValue,
    sortValue,
    filterValues,
    columns,
  ]);

  const renderTags = () => {
    const filtersArr = Object.keys(filterValues).map(key => {
      const col = findColumn(columns, key);
      return (
        <>
          {col.title}: {generateLabel(col, filterValues[key], locale)}
        </>
      );
    });

    return (
      <div className={`${getPrefixCls('apollo-table-selected-views-tags')}`}>
        {queryValue && <Tag>{`"${queryValue}"`}</Tag>}
        {filtersArr.map((item, index) => (
          // eslint-disable-next-line react/no-array-index-key
          <Tag key={index}>{item}</Tag>
        ))}
      </div>
    );
  };

  const handleSave = useCallback(async () => {
    await form.validateFields();
    // 编辑
    if (isEdit) {
      const newValue = [...value];
      const index = value.findIndex(item => item.id === activeKey);
      newValue[index] = {
        name: form.getFieldValue('label'),
        id: selectedViews.store ? activeKey : `savedSearch_${form.getFieldValue('label')}`,
        query: queryValue,
        orderBy: sortValue
          ? {
              field: sortValue.split(' ')[0],
              direction: sortValue.split(' ')[1] as OrderDirection,
            }
          : undefined,
        filters: filterValues,
      };
      const fn = () => {
        onChange(newValue);
        form.setFieldsValue({ label: '' });
        setVisible(false);
      };
      if (selectedViews.store) {
        setLoading(true);
        const { success } = await selectedViews.store.update({
          id: activeKey,
          name: form.getFieldValue('label'),
        });
        setLoading(false);
        if (success) {
          fn();
        }
      } else {
        fn();
        onActiveKeyChange(`savedSearch_${form.getFieldValue('label')}`);
      }

      // 保存
    } else {
      const addSelectedView = {
        name: form.getFieldValue('label'),
        query: queryValue,
        orderBy: sortValue
          ? {
              field: sortValue.split(' ')[0],
              direction: sortValue.split(' ')[1] as OrderDirection,
            }
          : null,
        filters: filterValues,
      };
      if (selectedViews.store) {
        setLoading(true);
        const { success, id } = await selectedViews.store.add(addSelectedView);
        setLoading(false);
        if (success && id) {
          const undefinedParams: any = {};
          Object.keys(searchParams).forEach(key => {
            undefinedParams[key] = undefined;
          });
          setSearchParams({
            ...undefinedParams,
            saved_search_id: id,
          });
          onChange([...value, { ...addSelectedView, id }]);
          onActiveKeyChange(id);
          form.setFieldsValue({ label: '' });
          setVisible(false);
        }
      } else {
        setSearchParams({
          selectedView: 'savedSearch',
        });
        onChange([
          ...value,
          { ...addSelectedView, id: `savedSearch_${form.getFieldValue('label')}` },
        ]);
        onActiveKeyChange(`savedSearch_${form.getFieldValue('label')}`);
        form.setFieldsValue({ label: '' });
        setVisible(false);
      }
    }
  }, [
    form,
    isEdit,
    value,
    queryValue,
    sortValue,
    filterValues,
    selectedViews.store,
    activeKey,
    onChange,
    onActiveKeyChange,
    searchParams,
    setSearchParams,
  ]);

  const handleRemove = useCallback(() => {
    setVisible(false);
    Modal.confirm({
      title: `${locale?.removeText} ${allSelectedViews.find(item => item.id === activeKey)?.name} ${
        locale?.filterText
      }`,
      content: locale?.deleteHelpText,
      okButtonProps: {
        danger: true,
      },
      onOk: async () => {
        const fn = () => {
          onChange(value.filter(item => item.id !== activeKey));
          onActiveKeyChange('all');
          setQueryValue('');
          setSortValue(
            defaultSortValue ? `${defaultSortValue.field} ${defaultSortValue.direction}` : '',
          );
          setFilterValues({});
        };
        if (selectedViews.store) {
          setLoading(true);
          const { success } = await selectedViews.store.remove(activeKey);
          setLoading(false);
          if (success) {
            fn();
          }
        } else {
          fn();
        }
      },
    });
  }, [
    activeKey,
    allSelectedViews,
    defaultSortValue,
    locale?.deleteHelpText,
    locale?.filterText,
    locale?.removeText,
    onActiveKeyChange,
    onChange,
    selectedViews.store,
    setFilterValues,
    setQueryValue,
    setSortValue,
    value,
  ]);

  return (
    <Popover
      trigger="click"
      content={
        <Form form={form} layout="vertical">
          {renderTags()}
          <Form.Item
            className={`${getPrefixCls('apollo-table-selected-views-input-label')}`}
            extra={!isEdit && locale?.viewSaveHelpText}
            label={locale?.viewName}
            name="label"
            rules={[
              {
                validator: (_, val) => {
                  if (!allSelectedViews.find(item => item.name === val)) {
                    return Promise.resolve();
                  }

                  return Promise.reject(new Error(locale?.viewError));
                },
              },
            ]}
            style={{ marginBottom: 0 }}
          >
            <Input autoComplete="off" style={{ marginBottom: 4, width: 300 }} />
          </Form.Item>

          <Form.Item
            noStyle
            shouldUpdate={(prevValues, currentValues) => prevValues.label !== currentValues.label}
          >
            {({ getFieldValue }) => (
              <div className={`${getPrefixCls('apollo-table-selected-views-button-wrapper')}`}>
                <Button
                  disabled={!getFieldValue('label')}
                  type="primary"
                  onClick={handleSave}
                  loading={loading}
                >
                  {locale?.saveViewText}
                </Button>
                {(activeKey.startsWith('savedSearch') || searchParams.saved_search_id) && (
                  <Button danger style={{ padding: 0 }} type="link" onClick={handleRemove}>
                    {locale?.deleteViewText}
                  </Button>
                )}
              </div>
            )}
          </Form.Item>
        </Form>
      }
      placement="bottomRight"
      visible={visible}
      onVisibleChange={vis => {
        if (vis) {
          form.setFieldsValue({ label: '' });
        } else {
          setVisible(false);
        }
      }}
    >
      <Button
        disabled={disabled}
        icon={isEdit ? <StarFilled /> : <StarOutlined />}
        onClick={() => setVisible(!visible)}
      >
        {/* eslint-disable-next-line no-nested-ternary */}
        {showSelectedViewButton ? null : isEdit ? locale?.editViewText : locale?.saveViewText}
      </Button>
    </Popover>
  );
};
