import { MinusCircleOutlined, PlusCircleOutlined } from '@ant-design/icons';
import { useControllableValue } from 'ahooks';
import type { FormInstance } from 'antd';
import { Form, Popconfirm, Space } from 'antd';
import type { SizeType } from 'antd/lib/config-provider/SizeContext';
import type { SpaceSize } from 'antd/lib/space';
import Link from 'antd/lib/typography/Link';
import { Flex } from 'antd5';
import { differenceWith, forEach, isEqual, isFunction, keys } from 'lodash';
import type { CSSProperties, ReactElement } from 'react';
import React, {
  Children,
  forwardRef,
  isValidElement,
  useCallback,
  useEffect,
  useImperativeHandle,
  useMemo,
} from 'react';
import { FormattedMessage } from 'umi';
import FormListItem from './FormListItem';
import { component } from './util';

const styles: Record<'link' | 'flex' | 'space' | 'form', CSSProperties> = {
  link: {
    fontSize: 18,
  },
  flex: {
    width: 50,
  },
  space: {
    width: '100%',
  },
  form: {
    width: '100%',
  },
};

const listFieldNameKey = 'dynamicform';

export type ChildrenType = React.ReactChildren | React.ReactElement | React.ReactNode | React.FC;
export type LayoutType = 'horizontal' | 'vertical';

export interface DynamicFormProps {
  /**
   * @description 只读
   */
  readOnly?: boolean;
  /**
   * @description 'layout'
   */
  labeLayout?: LayoutType;
  /**
   * @description value
   */
  value?: any;
  /**
   * @description onChange
   */
  onChange?: (value: any) => any;
  /**
   * @description 格式化
   */
  format?: (value: any) => any;
  /**
   * @description 增删模版
   */
  children: ChildrenType;
  /**
   * @description 行间距
   */
  spaceSize?: SpaceSize | [SpaceSize, SpaceSize];
  /**
   * @description 行表单项间距
   */
  flexGap?: CSSProperties['gap'] | SizeType;
}

export interface DynamicFormRef {
  validateFields: () => Promise<any>;
  form: () => FormInstance;
}

const DynamicForm = forwardRef<DynamicFormRef, DynamicFormProps>((props, ref) => {
  const {
    children,
    labeLayout = 'vertical',
    format,
    readOnly = false,
    spaceSize = 0,
    flexGap = 8,
  } = props;
  const [value, onChange] = useControllableValue(props);
  const [form] = Form.useForm();

  useImperativeHandle(ref, () => ({
    validateFields: async () => {
      const allValues = await form.validateFields();
      return allValues?.[listFieldNameKey];
    },
    form: () => form,
  }));

  // 表单项变更清除配置
  const changeCleans = useMemo(() => {
    const child = Array.isArray(children)
      ? children.map((item) => component(item))
      : component(children, value);
    const map = {};
    Children.forEach(child, (c) => {
      if (isValidElement(c as ReactElement)) {
        if (c?.props?.name && c?.props?.changeCleans) {
          map[c.props.name] = c.props.changeCleans;
        }
      }
    });
    return map;
  }, [children, value]);

  useEffect(() => {
    if (value && value?.length > 0) {
      form?.setFieldsValue({
        [listFieldNameKey]: value,
      });
    } else {
      form?.setFieldsValue({
        [listFieldNameKey]: [undefined],
      });
    }
  }, [value, form]);

  const valsChangeHandler = useCallback(
    (changedValues, allValues) => {
      const changedData: any[] = changedValues?.[listFieldNameKey];
      const allData: any[] = allValues?.[listFieldNameKey];
      let index = -1;
      const resetprops = {};
      if (
        differenceWith(allData, value, isEqual)?.filter((item) => !!item)?.length === 1 &&
        changedData?.length > 0
      ) {
        changedData.forEach((item: any, i: number) => {
          if (item) {
            index = i;
            forEach(changeCleans[keys(item)?.[0]], (k) => {
              resetprops[k] = undefined;
            });
          }
        });
      }
      const vals = allData?.map((item: any, i: number) => ({
        ...item,
        ...(i === index ? resetprops : {}),
      }));
      onChange(isFunction(format) ? format(vals) : vals);
      form.validateFields();
    },
    [changeCleans, form, format, onChange, value],
  );

  return (
    <Form
      disabled={readOnly}
      layout={labeLayout}
      form={form}
      autoComplete={'off'}
      style={styles.form}
      onValuesChange={valsChangeHandler}
    >
      <Form.List name={listFieldNameKey}>
        {(fields, { add, remove }) => (
          <Space direction={'vertical'} style={styles.space} size={spaceSize}>
            {fields.map((field, index) => (
              <Flex key={field.key} justify={'space-between'} align={'center'} gap={flexGap}>
                <FormListItem field={field} value={value} index={index} layout={labeLayout}>
                  {children}
                </FormListItem>

                {!Boolean(readOnly) && (
                  <Form.Item label={labeLayout === 'vertical' && index === 0 ? ' ' : ''}>
                    <Flex justify={'flex-end'} align={'center'} gap={14} style={styles.flex}>
                      <Popconfirm
                        title={<FormattedMessage id={'base.common.delete.confirm'} />}
                        disabled={fields.length <= 1}
                        onConfirm={() => remove(field.name)}
                      >
                        <Link type={'danger'} style={styles.link} disabled={fields.length <= 1}>
                          <MinusCircleOutlined />
                        </Link>
                      </Popconfirm>

                      <Link style={styles.link} onClick={() => add(undefined, index + 1)}>
                        <PlusCircleOutlined />
                      </Link>
                    </Flex>
                  </Form.Item>
                )}
              </Flex>
            ))}
          </Space>
        )}
      </Form.List>
    </Form>
  );
});

export default DynamicForm;
