import React, { useContext, isValidElement } from 'react';
import { Form } from 'antd';
import { concat, map, get, pick, omit, mapKeys } from 'lodash';
import warning from 'warning';
import { YForm, mergeWithDom } from '..';
import ItemChildren from './ItemChildren';
import Items, { YFormRenderChildren, YFormDataSource } from './Items';
import { getParentNameData } from './utils';
import { YFormInstance } from './Form';

const Item: React.FC<YFormDataSource> = (props) => {
  // 这里解析出来的参数最好不要在 scenes 中更改
  const { scenes, ...rest } = props;

  const { name, children } = rest;
  const formProps = useContext(YForm.YFormContext);

  const {
    itemsType = {},
    onDeFormatFieldsValue,
    oldValues,
    getScene,
    onFormatFieldsValue,
  } = formProps;

  const itemsProps = useContext(YForm.YFormItemsContext);
  const { scenes: thisScenes } = itemsProps;

  const listContext = useContext(YForm.ListContent);
  const { prefixName } = listContext;

  // List 会有拼接 name ,这里获取 all name path
  const allName = prefixName ? concat(prefixName, name) : name;

  const mergeProps = mergeWithDom(
    {},
    pick(formProps, ['scenes', 'offset', 'disabled']),
    itemsProps,
    props,
  );

  if ('isShow' in props && !props.isShow) return null;

  const _scenes = mergeWithDom({}, thisScenes, scenes);
  let _props = mergeWithDom({}, mergeProps, rest, {
    offset: (props.offset || 0) + (itemsProps.offset || 0),
  });

  let _componentProps = { ...props.componentProps };

  const typeProps = get(itemsType, props.type) || {};
  // 原类型
  typeProps.type = props.type;
  const defaultData = {
    formProps,
    itemsProps: mergeProps,
    itemProps: _props,
    componentProps: _componentProps,
    typeProps,
  };

  // 参数修改
  const _defaultData = defaultData;
  const { modifyProps } = typeProps;
  if (modifyProps) {
    mergeWithDom(_defaultData, modifyProps(defaultData));
  }

  mapKeys(_scenes, (value: boolean, key: string) => {
    if (value && getScene[key] && getScene[key].item) {
      const data = getScene[key].item(_defaultData);
      if (data) {
        _defaultData.itemProps = { ..._defaultData.itemProps, ...data.itemProps };
        _defaultData.componentProps = { ..._defaultData.componentProps, ...data.componentProps };
      }
    }
  });

  _props = { ..._defaultData.itemProps };
  _componentProps = _defaultData.componentProps;

  const { type, dataSource, componentProps, format, ...formItemProps } = _props;
  const _formItemProps = formItemProps;
  const { isShow, shouldUpdate } = _formItemProps;

  const { deFormat } = _defaultData.itemProps;

  // 获取前格式化
  if (deFormat) {
    onDeFormatFieldsValue({ name: allName, format: deFormat });
    if (oldValues && _scenes.diff) {
      _defaultData.itemProps = {
        oldValue: deFormat(
          get(oldValues, allName),
          getParentNameData(oldValues, allName),
          oldValues,
        ),
        ..._defaultData.itemProps,
      };
    }
  }

  // 提交前格式化
  if (format) {
    let _format = [];
    if (typeof format === 'function') {
      _format = [{ name: allName, format }];
    } else {
      _format = map(format, (item) => {
        const _item = { ...item };
        if (item.name) {
          _item.name = prefixName ? concat(prefixName, item.name) : item.name;
        }
        return _item;
      });
    }
    onFormatFieldsValue(_format);
  }

  let _children;
  // 默认用 FormItem 包裹
  let _hasFormItem = true;
  const thisComponentProps = _componentProps;
  if (type) {
    const _fieldData = itemsType[type];
    if (_fieldData) {
      const { component } = _fieldData;
      _hasFormItem = 'hasFormItem' in _fieldData ? _fieldData.hasFormItem : _hasFormItem;
      const _component = children || component;
      _children = isValidElement(_component)
        ? React.cloneElement(_component, {
            ...(_component.props as Record<string, any>),
            ...thisComponentProps,
          })
        : _component;
    } else {
      warning(false, `[YFom.Items] ${type} 类型未找到`);
    }
  } else {
    // 没有 type 单独有 dataSource 情况
    if (dataSource) {
      _children = (
        <Items scenes={_scenes} {...thisComponentProps}>
          {dataSource}
        </Items>
      );
    } else {
      _children = isValidElement(children)
        ? React.cloneElement(children, { ...children.props, ...thisComponentProps })
        : children;
    }
  }
  const domChildren =
    typeof _children === 'function'
      ? (form: YFormInstance) => {
          return (
            <Items noStyle scenes={_scenes}>
              {(_children as YFormRenderChildren)(form)}
            </Items>
          );
        }
      : _children;
  let dom = domChildren;
  if (_hasFormItem) {
    dom = (
      <ItemChildren
        {...omit(_formItemProps, [
          'component',
          'scenes',
          'viewProps',
          'deFormat',
          'format',
          'oldValue',
          'items',
          'offset',
          'hideLable',
        ])}
      >
        {domChildren}
      </ItemChildren>
    );
  }

  const render = (props?: any) => {
    return (
      <YForm.YFormItemContext.Provider value={mergeWithDom(omit(_props, ['children']), props)}>
        {dom}
      </YForm.YFormItemContext.Provider>
    );
  };

  if (shouldUpdate) {
    let reRender = false;
    return (
      <Form.Item noStyle shouldUpdate={shouldUpdate}>
        {(form) => {
          if (typeof isShow === 'function') {
            const fieldsValue = form.getFieldsValue(true);
            const parentValue = getParentNameData(fieldsValue, name);
            if (!isShow(parentValue, fieldsValue)) {
              return;
            }
          }
          reRender = !reRender;
          return render({ reRender });
        }}
      </Form.Item>
    );
  }
  return render();
};

export default Item;