import React, { useState, useRef, useEffect, useMemo, useCallback, useContext } from "react";
import { Tooltip, Table, Space, Popover, Input, Button, Form, Checkbox } from "antd";
import { QuestionCircleOutlined, PlusOutlined, DeleteOutlined } from '@ant-design/icons';
import { useClickAway } from 'ahooks';
import update from 'immutability-helper';
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';

import DebounceInput from "../../../Model/Component/DebounceInput";
import { inputWidth } from "../../../../../util";
import { DragableBodyRow, DatatypeInput } from "../../../Model/Component/ImportActionTable";
import { dispatch } from "../../../../../model";
import { EditTemplateContext } from "./UpdateTemplateModal";

const InputDebounce = DebounceInput(300)(Input);

const FieldTypeComp = (props) => {
  const {dataType = {}} = props;
  const [value, setValue] = useState('');

  useEffect(() => {
    try {
      let dataTypeJson = JSON.parse(dataType);

      if ((dataTypeJson?.name==='Char'||dataTypeJson?.name==='Varchar') && dataTypeJson?.parameterValues?.length>0) {
        setValue(`${dataTypeJson?.name||''}(${(dataTypeJson?.parameterValues[0]?dataTypeJson?.parameterValues[0]:0)})`);      
      } else if ((dataTypeJson?.name==='Decimal'||dataTypeJson?.name==='Numeric') && dataTypeJson?.parameterValues?.length>1) {
        setValue(`${dataTypeJson?.name||''}(${(dataTypeJson?.parameterValues[0]?dataTypeJson?.parameterValues[0]:0)},${(dataTypeJson?.parameterValues[1]?dataTypeJson?.parameterValues[1]:0)})`);
      } else {
        setValue(dataTypeJson?.name||'');
      }
    } catch(error) {
      setValue('');
    }
  }, [dataType])

  return (
    <span>{value}</span>
  )
}

export const EditableCell = ({
  editing,
  dataIndex,
  colTitle,
  inputType,
  record,
  index,
  datatypes,
  require,
  children,
  ...restProps
}) => {

  let editingComponent = null;
  if (editing) {
    if (dataIndex !== 'dataType') {

      const inputNode = inputType === 'check' ? <Checkbox /> : <InputDebounce />

      editingComponent = (
        <Form.Item
          name={dataIndex}
          style={{
            margin: 0,
          }}
          valuePropName={(inputType==='check')? 'checked': 'value'}
          rules={[
            {
              required: (require===null)?false:require,
              message: `请输入${colTitle}!`,
            },
          ]}
        >
        { inputNode }
        </Form.Item>
      );
    } else {

      editingComponent = (
        <Form.Item
          name={dataIndex}
          style={{
            margin: 0,
          }}
          valuePropName={'value'}
          rules={[
            {
              required: (require===null)?false:require,
              message: `请输入${colTitle}!`,
            },
          ]}
        >
          <DatatypeInput datatypes={datatypes} />
        </Form.Item>
      )
    }
  }


  return (
    <td {...restProps}>
      {editing ? (
        editingComponent
      ) : (
        children
      )}
    </td>
  );
};

const UpdateField = (props) => {
  const {editable = true, template, visible, onChange} = props;
  const [data, setData] = useState([]);
  const [keyword, setKeyword] = useState('');
  const [editingKey, setEditingKey] = useState(null);
  const [supportedDatatypes, setSupportedDatatypes] = useState([]);
  const [loading, setLoading] = useState(false);
  const [form] = Form.useForm();
  const tableRef = useRef(null);
  const dataRef = useRef([]);
  const editingKeyRef = useRef(null);
  const { attrIsEditingFunction } = useContext(EditTemplateContext);

  const cols = [
    {
      title: '序号',
      dataIndex: 'key',
      editable: false,
      width: 60,
      render: (_, __, index) => {
        return (index+1).toString();
      }
    },
    {
      title: '中文名称',
      width: 200,
      dataIndex: 'cnName',
      editable: true,
      ellipsis: true,
      require: true,
      render: (text, _, __) => {
        return (
          <Tooltip title={text||''}>
            <span>{text}</span>
          </Tooltip>
        )
      }
    },
    {
      title: '英文名称',
      width: 200,
      dataIndex: 'name',
      editable: true,
      ellipsis: true,
      require: true,
      render: (text, record, index) => {
        return (
          <Tooltip title={text||''}>
          <span style={{ fontWeight: 'bold' }} >{text}</span>
          </Tooltip>
        )
      }
    },
    {
      title: '类型',
      width: (editingKey!==null)?250:150,
      dataIndex: 'dataType',
      editable: true,
      ellipsis: true,
      require: true,
      render: (_, record, __) => {
        return <FieldTypeComp dataType={record?.dataType} />;
      }
    },
    {
      title: '业务含义',
      dataIndex: 'comment',
      editable: true,
      ellipsis: true,
      require: true,
      width: 200,
      render: (text, _, __) => {
        return (
          <Tooltip title={text||''}>
            <span>{text}</span>
          </Tooltip>
        )
      }
    }
  ];

  const actionCol = {
    title: '操作',
    dataIndex: 'action',
    width: 90,
    fixed: 'right',
    render: (_, record) => {
      return (
        <React.Fragment>
        {
          editable && <React.Fragment> 
          {
            <React.Fragment>
              <Button 
                className='mr-3' 
                size='small'
                type='text' 
                icon={<DeleteOutlined style={{ color: 'red' }} />} 
                onClick={(event) => { 
                  event.stopPropagation();
                  removeItem(record); 
                }}
              />
            </React.Fragment>
          }
          </React.Fragment> 
        }
        </React.Fragment>
      )
    },
  };

  useEffect(() => {
    if (visible) {
      setEditingKey(null);
      editingKeyRef.current = null;
      if (!template) {
        setData([]);
        dataRef.current = [];
      } else {
        getFileds();
      }
    }
    //eslint-disable-next-line react-hooks/exhaustive-deps
  }, [visible, template])

  const columns = useMemo(() => {
    const newColumns = [...cols];

    if (editable) {
      newColumns.push(actionCol);
    }

    return newColumns;
    //eslint-disable-next-line react-hooks/exhaustive-deps
  }, [editable, data, editingKey]); 

  useClickAway(() => {
    save();
  }, tableRef);

  useEffect(() => {
    getSupportedDatatypes();
  }, [])

  useEffect(() => {
    attrIsEditingFunction && attrIsEditingFunction(editingKey!=null);
    //eslint-disable-next-line react-hooks/exhaustive-deps
  }, [editingKey])

  const filterData = useMemo(() => {
    return (data||[]).filter(item => (item?.name||'').indexOf(keyword)!==-1 || (item.cnName).indexOf(keyword)!==-1);
  }, [keyword, data])

  const isEditing = (record) => record?.name === editingKey;

  const getSupportedDatatypes = () => {
    dispatch({
      type: 'msd.getTypes',
      callback: data => {
        setSupportedDatatypes(data||[]);
      }
    });
  }

  const getFileds = () => {
    setLoading(true);
    dispatch({
      type: 'msd.getColumns',
      payload: {
        params: {
          modelId: template?._id||''
        }
      },
      callback: data => {
        setLoading(false);

        function compare(val1, val2) {
          var a = val1.seq;
          var b = val2.seq;
          return (a - b);
        }
    
        (data||[]).sort(compare);
        setData(data||[]);
        dataRef.current = data||[];
        onChange && onChange(data||[]);
      },
      error: () => {
        setLoading(false);
      }
    });
  }

  const onAddClick = (event) => {
    event.stopPropagation();  

    save().then(result => {
      if (result) {
        setKeyword('');

        const newData = [...dataRef.current, {name: ''}];
        
        setData(newData);
        dataRef.current = newData;
        editItem(newData[newData.length-1]);
    
        setTimeout(() => {
          document.getElementById(`field-`)?.scrollIntoView();
        }, 200)
      }
    })
  }

  const removeItemLogic = (record) => {
    const newData = [...data];
    const index = newData.findIndex((item) => record.name === item.name);

    if (index !== -1) {
      newData.splice(index, 1);
    }

    setData(newData);
    dataRef.current = newData;
    onChange && onChange(newData);
  }

  const removeItem = (record) => {
    if (record.name !== editingKey) {
      removeItemLogic(record);
    } else {
      setEditingKey(null);
      editingKeyRef.current = null;
      removeItemLogic(record);
    }
  }

  const onSearchInputChange = (value) => {
    save().then(result => {
      if (result) {
        setKeyword(value);
      } 
    });
  }

  const editItemLogic = (record) => {
    form.resetFields();

    try {
      let dataTypeJson = JSON.parse(record?.dataType);

      form.setFieldsValue({...record, dataType: dataTypeJson});
      setEditingKey(record?.name);
      editingKeyRef.current = record?.name;
    } catch {
      form.setFieldsValue({...record, dataType: {}});
      setEditingKey(record?.name);
      editingKeyRef.current = record?.name;
    }
  }

  const editItem = (record) => {
    save().then((result) => {
      if (result) {
        editItemLogic(record);
      }
    }); 
  };

  const save = async() => {
    try {
      if (editingKeyRef.current !== null) {
        const row = await form.validateFields();

        if ((row.dataType.name||'')==='') {
          form.setFields([{ name: 'dataType', errors: ['必须选择类型'] }]);
          return;
        }

        (row.dataType.parameterNames||[]).forEach((parameterName, index) => {
          if (!row.dataType.parameterValues[index] || row.dataType.parameterValues[index]==='') {
            row.dataType.parameterValues[index] = 0;
          }
        })

        const newData = [...dataRef.current];
        const index = newData.findIndex((item) => editingKeyRef.current === item.name);
       
        const newDataExcludeSelf = [...dataRef.current];
        newDataExcludeSelf.splice(index, 1);  
        //判断字段名称是否唯一
        let _index = (newDataExcludeSelf||[]).findIndex(item => item.name === row.name);

        if (_index !== -1) {
          form.setFields([{ name: 'name', errors: ['字段名称不能重复'] }]);
          return false;
        }

        row.dataType = JSON.stringify(row.dataType);

        const item = newData[index];
        let attribute = { ...item, ...row};
        newData.splice(index, 1, attribute);

        setEditingKey(null);
        editingKeyRef.current = null;

        setData(newData);
        dataRef.current = newData;

        onChange && onChange(newData);
      }

      return true;
    } catch (errInfo) {
      console.log('Validate Failed:', errInfo);
      return false;
    }
  };

  const moveRow = useCallback(
    (dragIndex, hoverIndex) => {
      const dragRow = data[dragIndex];
      const newData = update(data, {
        $splice: [
          [dragIndex, 1],
          [hoverIndex, 0, dragRow],
        ],
      });

      setData(newData);
      dataRef.current = newData;
      onChange && onChange(newData);
      //eslint-disable-next-line react-hooks/exhaustive-deps
    }, [data]);

  const onTableRow = (record, index) => {
    let rowParams = {
      index,
      id: `field-${record.name}`,
    };

    if (editable) {
      if (!isEditing(record)) {
        rowParams = {...rowParams, onClick: (event) => {
            event.stopPropagation();
            editItem(record);
          }
        }

        if (keyword.length===0) {
          rowParams = {...rowParams, moveRow};
        }
      }
    }

    return rowParams;
  }

  const mergedColumns = columns.map((col) => {
    if (!col.editable) {
      return col;
    }

    return {
      ...col,
      onCell: (record) => ({
        record,
        dataIndex: col.dataIndex,
        colTitle: col.title,
        editing: isEditing(record),
        datatypes: supportedDatatypes,
        require: col.require
      }),
    };
  });

  return (
    <div>
      <div className='d-flex mb-3' style={{ justifyContent: 'space-between' }}>
        <Space>
          <h3 style={{ marginBottom: 0 }}>字段信息</h3>
          { 
            editable && <Popover content='点击行进行编辑,表格可以通过拖拽来排序'>
              <QuestionCircleOutlined className='pointer' /> 
            </Popover> 
          }
        </Space>
        <Space>
          { 
            editable && <Button onClick={onAddClick}>新建</Button>
          }
          <div className='d-flex' style={{ alignItems: 'center' }}>
            <InputDebounce 
              placeholder="请输入中文名称或者英文名称" 
              allowClear 
              value={keyword}
              onChange={onSearchInputChange} 
              style={{ width: inputWidth }}
            />
          </div>
        </Space>
      </div>
      <div id="containerId" ref={tableRef}>
        <DndProvider backend={HTML5Backend} >
          <Form form={form} component={false}>
            <Table
              rowKey='_id'
              loading={loading}
              dataSource={filterData}
              columns={mergedColumns}
              pagination={false}
              components={{
                body: {
                  cell: EditableCell,
                  //编辑或者搜索状态下不允许拖动
                  row: (editable&&editingKey===null&&keyword==='')?DragableBodyRow:null,
                },
              }}
              onRow={onTableRow}
            />
          </Form>
        </DndProvider>
      </div>
    </div>
  );
}

export default UpdateField;