import React, { useState, useEffect, useRef } from 'react';
import { Spin } from 'antd';
import LocalStorage from 'local-storage';

import ImportActionHeader from './ImportActionHeader'; 
import { ImportActionTable } from './ImportActionTable';
import ImportActionIndex from './ImportActionIndex';
import { getQueryParam } from '../../../../util';
import { Action } from '../../../../util/constant';

import { dispatch } from '../../../../model'; 

const ImportAction = (props) => {
  const { action, hints, onChange, form, modelerId, terms, ddl, roughModelerData, versionId, permitCheckOut } = props;

  const [ constraints, setConstraints ] = useState([]);
  const [ constraint, setConstraint ] = useState({});
  const [ templates, setTemplates ] = useState([]);
  const [ template, setTemplate ] = useState({});
  const [ modelerData, setModelerData ] = useState(null);
  const [ supportedDatatypes, setSupportedDatatypes ] = useState([]);
  const [ supportedPartitionTypes, setSupportedPartitionTypes ] = useState([]); 
  const [ supportedIndextypes, setSupportedIndextypes ] = useState([]);
  const [ validateReports, setValidateReports ] = useState([]);
  const [ loading, setLoading ] = useState(false);

  const mountRef = useRef(true);
  const modelerDataRef = useRef(null);

  useEffect(() =>{
 
    if ((action||'')==='') return;

    if (!mountRef.current && action === 'edit' && !permitCheckOut) {
      return;
    }

    //流程打开模型详情的情况下,id由-1变成-2,会再次触发获取模型详情.这里直接return掉
    if (!mountRef.current && action === 'flow') {
      return;
    }

    mountRef.current = false;
      
    //初始化form状态
    if (action==='add'||action==='edit'||action==='flow') {
      form.resetFields();
    }

    if (action === 'detail'|| action ==='flow' || action === 'detail-version') {
       //把数据表结构中的数据清空,解决性能问题
        const newModelerData = { ...modelerData, easyDataModelerDataModelAttributes: [] };

        onChange && onChange(newModelerData);
        setModelerData(newModelerData);
        modelerDataRef.current = newModelerData;
    }

    setLoading(true);

    dispatch({
      type: 'datamodel.getAllConstraintsAndTemplates',
      callback: data => {
        setConstraints(data.constraints||[]);
        setTemplates(data.templates||[]);
        if (action === 'add') {
          setConstraint((data.constraints||[]).length>0?data.constraints[0]:{});
          setTemplate({});
          if ((hints||[]).length>0) {
            getDraft((data.constraints||[]).length>0?data.constraints[0]:{}, {} ,hints);
          } else if ((ddl||'').length>0) {
            getDraftUsingDDL((data.constraints||[]).length>0?data.constraints[0]:{}, {} ,ddl);
          } else if ((modelerId||'')!=='') {
            getCurrentDataModel();
          } else if (roughModelerData) {
            setLoading(false);
            getExtraData(roughModelerData);
          } else {
            getDraft((data.constraints||[]).length>0?data.constraints[0]:{}, {} ,[]);
          }
        } else if(action === 'edit' || action === 'detail' || action ==='flow' || action === 'detail-version') {
          getCurrentDataModel();
        }
      },
      error: () => {
        setLoading(false);
      }
    })
    //eslint-disable-next-line react-hooks/exhaustive-deps
  }, [action, hints, modelerId, ddl ]);

  const getDraft = (_constraint, _template, _hints) => { 
    dispatch({
      type: 'datamodel.getDraft',
      payload: {
        data: {
          hints: _hints,
          modelerModelingConstraint: _constraint,
          easyDataModelerModelingTemplate: _template
        }   
      },
      callback: data => {
        setLoading(false);
        getExtraData(data);
      },
      error: () => {
        setLoading(false);
      }
    })
  }

  const getDraftUsingDDL = (_constraint, _template, _ddl) => { 
    dispatch({
      type: 'datamodel.getDraftUsingDDL',
      payload: {
        data: {
          ddl: _ddl,
          modelerModelingConstraint: _constraint,
          easyDataModelerModelingTemplate: _template
        }   
      },
      callback: data => {
        setLoading(false);
        getExtraData(data);
      },
      error: () => {
        setLoading(false);
      }
    });
  }

  const getConsult = (data) => {
    dispatch({
      type: 'datamodel.getConsult',
      payload: {
        data  
      },
      callback: data => {
        let newModelerData = {...(data||{})};
        newModelerData = { ...newModelerData, ...getConsistentKeys(newModelerData) };

        setModelerData(newModelerData);
        modelerDataRef.current = newModelerData;

        onChange && onChange(newModelerData);
        validateDataModel(newModelerData);

      }
    })
  }

  const getCurrentDataModel = () => {

    if ((modelerId||'') === '') {
      setLoading(false);
      return;
    }

    let type = 'datamodel.getDataModel';

    let params = {
      id: modelerId||''
    };

    if (action === 'add') {
      type = 'datamodel.modelCopy';
    } else if (action === 'flow') {
      type = 'datamodel.getDataModelWithRecommendedDefinitionAndTermDiscovery';
    } else if (action === 'detail-version') {
      type = 'datamodel.getDataModelByVersionId';
      params = {
        params: {
          id: modelerId||'',
          versionId
        }
      }
    } else if (action==='edit' && permitCheckOut) {
      type = 'datamodel.checkOutDataModel';
    } else if (action==='edit') {
      const _action = getQueryParam(Action, props.location.search);

      if (_action === 'flow') {
        params.ignoreNamespace = true;
      }
    } 

    dispatch({
      type,
      payload: params,
      callback: data => {
        if (action==='edit' && permitCheckOut) {
          LocalStorage.set('modelChange', !(LocalStorage.get('modelChange')||false));
        }

        setLoading(false);
        getExtraData(data);
      },
      error: () => {
        setLoading(false);
      }
    })
  }

  const getExtraData = (data) => {
    const newModelerData = { ...(data||{}), ...getConsistentKeys(data||{}) };

    setModelerData(newModelerData||{});
    modelerDataRef.current = newModelerData||{};

    setConstraint(newModelerData.easyDataModelerModelingConstraint||{});
    setTemplate(newModelerData.easyDataModelerModelingTemplate||{});
    onChange && onChange(newModelerData||{});
    getSupportedDatatypes();
    getSupportedPartitionTypes();
    getSupportedIndextypes();

    if (newModelerData) {
      form.setFieldsValue({ 
        cnName: newModelerData.cnName||'',
        name: newModelerData.name||'',
        remark: newModelerData.remark||'',
        easyDataModelerModelingConstraint: newModelerData.easyDataModelerModelingConstraint||'',
        easyDataModelerModelingTemplate: newModelerData.easyDataModelerModelingTemplate||'',
        dataResidence: newModelerData.dataResidence||'',
        tableType: newModelerData.tableType||'',
        dataUpdatingTiming: newModelerData.dataUpdatingTiming||'',
        maintenanceRecords: newModelerData.maintenanceRecords||'',
        dataLoadingStrategy: newModelerData.dataLoadingStrategy||'',
        primaryKeysDescription: newModelerData.primaryKeysDescription||'',
        distributionKeysDescription: newModelerData.distributionKeysDescription||'',
        dataCircumstances: newModelerData.dataCircumstances||'',
        partitionsDescription: newModelerData.partitionsDescription||'',
        semiPrimaryKeysDescription: newModelerData.semiPrimaryKeysDescription||'',
      });
    }
    
    validateDataModel(newModelerData||{});
  }

  const onConstraintChange = (value) => {
    let currentConstraint = null;
    
    (constraints||[]).forEach((_constraint, index) => {
      if (_constraint.name === value) {
        currentConstraint = _constraint;
      }
    });

    if (!currentConstraint) return;

    form.setFieldsValue({ 
      easyDataModelerModelingConstraint: currentConstraint
    });
    const newModelerData = {...modelerData, easyDataModelerModelingConstraint: currentConstraint };
    setModelerData(newModelerData);
    modelerDataRef.current = newModelerData;

    onChange && onChange(newModelerData);

    setConstraint(currentConstraint);
    getConsult(newModelerData);
  }

  const onTemplateChange = (value) => {
    let currentTemplate = null;
    
    (templates||[]).forEach((_template, index) => {
      if (_template.name === value) {
        currentTemplate = _template;
      }
    });

    form.setFieldsValue({ 
      easyDataModelerModelingTemplate: currentTemplate||{}
    });

    const newModelerData = {...modelerData, easyDataModelerModelingTemplate: currentTemplate };

    setModelerData(newModelerData);
    modelerDataRef.current = newModelerData;

    onChange && onChange(newModelerData);

    setTemplate(currentTemplate);
    getConsult(newModelerData);
  }

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

  const getSupportedPartitionTypes = () => {
    dispatch({
      type: 'datamodel.getSupportedPartitionTypes',
      payload: {
        excludeBuiltin: false
      },
      callback: data => {
        setSupportedPartitionTypes(data||[]);
      }
    });
  }

  const getSupportedIndextypes = () => {
    dispatch({
      type: 'datamodel.getSupportedIndextypes',
      callback: data => {
        setSupportedIndextypes(data||[]);
      }
    });
  }

  const onHeaderChange = (changedValues, allValues) => {

    let newModelerData = {...modelerData, ...allValues};

    if (newModelerData.easyDataModelerModelingTemplate==='' || newModelerData.easyDataModelerModelingTemplate==={}) {
      newModelerData.easyDataModelerModelingTemplate = null;
    } 

    //主键不允许为空
    if (changedValues.hasOwnProperty('easyDataModelerPrimaryKey')) {
      (newModelerData.easyDataModelerDataModelAttributes||[]).forEach(attribute => {
        let ownPrimaryKey = false;
        if (newModelerData?.easyDataModelerPrimaryKey) {
          ownPrimaryKey = (newModelerData.easyDataModelerPrimaryKey.filter(item => item.name===attribute.name).length>0);
        }

        if (ownPrimaryKey) {
          attribute.notNull = true;
        }
      })
    }

    //类主键自动创建索引
    let autoEasyDataModelerIndexOrders = [];
    (newModelerData.easyDataModelerSemiPrimaryKey||[]).forEach(item => {
      autoEasyDataModelerIndexOrders.push('ASC');
    });
    let autoEasyDataModelerIndex = {
      "name": `i_pk_${newModelerData.name}`,
      "indextype": {
          "name": "btree",
          "displayName": "B-tree",
          "supportedDBTypes": [
            "Greenplum",
            "MySQL"
          ],
          "default": true
      },
      "indexedAttributeOrders": [...autoEasyDataModelerIndexOrders],
      "indexedEasyDataModelAttributes": [...newModelerData.easyDataModelerSemiPrimaryKey],
      "unique": false
    };

    let newEasyDataModelerIndices = [];

    (newModelerData.easyDataModelerIndices||[]).forEach((easyDataModelerIndex, index) => {
      if (easyDataModelerIndex.name!==`i_pk_${modelerDataRef.current?.name}` && easyDataModelerIndex.name!==`i_pk_${newModelerData.name}`) {
        newEasyDataModelerIndices.push(easyDataModelerIndex);
      }
    });

    newEasyDataModelerIndices.push(autoEasyDataModelerIndex);

    newEasyDataModelerIndices = newEasyDataModelerIndices.filter(item => (item.indexedEasyDataModelAttributes||[]).length > 0);

    newModelerData = {...newModelerData, easyDataModelerIndices: newEasyDataModelerIndices};

    setModelerData(newModelerData);
    modelerDataRef.current = newModelerData;

    onChange && onChange(newModelerData);

    if (changedValues.hasOwnProperty('name') || changedValues.hasOwnProperty('cnName')) {
      validateDataModel(newModelerData);
    }
  }

  //validate 是否需要对字段进行校验
  const onTableChange = (data, validate=false) => { 

    let newModelerData = {...modelerDataRef.current, ...{easyDataModelerDataModelAttributes: data}};

    newModelerData = { ...newModelerData, ...getConsistentKeys(newModelerData) };
    
    setModelerData(newModelerData);
    modelerDataRef.current = newModelerData;

    onChange && onChange(newModelerData);

    if (validate) {
      validateDataModel(newModelerData);
    }
  }

  const validateDataModel = (data) => {

    const row = form.getFieldsValue();

    dispatch({
      type: 'datamodel.validateDataModel',
      payload: {
        data: (action==='detail'||action==='flow'||action==='detail-version')?data:{ ...data, ...{ name: row.name||'', cnName: row.cnName||'' } },
      },
      callback: _data => {
        setValidateReports(_data||[]);
      }
    })
  }

  const onIndexChange = (data, validate=false) => {
    const newModelerData = {...modelerDataRef.current, easyDataModelerIndices: data};

    setModelerData(newModelerData);
    modelerDataRef.current = newModelerData;

    onChange && onChange(newModelerData);

    if (validate) {
      validateDataModel(newModelerData);
    }
  }

  const getConsistentKeys = (newModelerData) => {

    //分布键
    let newDistribution = [];

    (newModelerData.easyDataModelerDistributionKey||[]).forEach((item, index) => {
      const _index = (newModelerData.easyDataModelerDataModelAttributes||[]).findIndex(_item => item.iid === _item.iid);

      if (_index !== -1) {
        newDistribution.push({...newModelerData.easyDataModelerDataModelAttributes[_index]});
      } 
    })

     //主键
     let newPrimary = [];

     (newModelerData.easyDataModelerPrimaryKey||[]).forEach((item, index) => {
       const _index = (newModelerData.easyDataModelerDataModelAttributes||[]).findIndex(_item => item.iid === _item.iid);
 
       if (_index !== -1) {
        newPrimary.push({...newModelerData.easyDataModelerDataModelAttributes[_index]});
       } 
     })

    //分区
    let newPartition = {...(newModelerData.partition||[])};

    const newKeys = [];

    (newPartition.keys||[]).forEach((item, index) => {
      const _index = (newModelerData.easyDataModelerDataModelAttributes||[]).findIndex(_item => item.iid === _item.iid);

      if (_index !== -1) {
        newKeys.push({...newModelerData.easyDataModelerDataModelAttributes[_index]});
      } 
    })

    newPartition.keys = newKeys;

    if ((newKeys||[]).length === 0) {
      newPartition = null;
    }

    //类主键
    let newSemiPrimary = [];

    (newModelerData.easyDataModelerSemiPrimaryKey||[]).forEach((item, index) => {
      const _index = (newModelerData.easyDataModelerDataModelAttributes||[]).findIndex(_item => item.iid === _item.iid);

      if (_index !== -1) {
        newSemiPrimary.push({...newModelerData.easyDataModelerDataModelAttributes[_index]});
      } 
    })

    //索引
    let newEasyDataModelerIndices = [...(newModelerData.easyDataModelerIndices||[])];

    (newModelerData.easyDataModelerIndices||[]).forEach((easyDataModelerIndex, index) => {

      const newIndexedEasyDataModelAttributes = [], newIndexedAttributeOrders = [];

      (easyDataModelerIndex.indexedEasyDataModelAttributes||[]).forEach((indexedEasyDataModelAttribute, _index) => {
        const __index = (newModelerData.easyDataModelerDataModelAttributes||[]).findIndex(item => item.iid === indexedEasyDataModelAttribute.iid);

        if (__index !== -1) {
          newIndexedEasyDataModelAttributes.push({...newModelerData.easyDataModelerDataModelAttributes[__index]});
          newIndexedAttributeOrders.push(easyDataModelerIndex.indexedAttributeOrders[_index]);
        } 
      })

      const item = newEasyDataModelerIndices[index];
      newEasyDataModelerIndices.splice(index, 1, {...item, ...{ indexedEasyDataModelAttributes: newIndexedEasyDataModelAttributes, indexedAttributeOrders: newIndexedAttributeOrders }} )
    })

    newEasyDataModelerIndices = newEasyDataModelerIndices.filter(item => (item.indexedEasyDataModelAttributes||[]).length > 0);

    return { partition: newPartition, easyDataModelerDistributionKey: newDistribution, easyDataModelerPrimaryKey: newPrimary, easyDataModelerIndices: newEasyDataModelerIndices, easyDataModelerSemiPrimaryKey: newSemiPrimary};
  }

  return (
    <Spin spinning={loading}>
      <ImportActionHeader 
        form={form}
        editable={action!=='detail'&&action!=='flow'&&action!=='detail-version'} 
        modelerData={modelerData||{}} 
        constraints={constraints}
        templates={templates}
        validateReports={validateReports}
        onTemplateChange={onTemplateChange}
        onConstraintChange={onConstraintChange}
        onChange={onHeaderChange}
        terms={terms}
        supportedPartitionTypes={supportedPartitionTypes} 
      />   
      <ImportActionTable 
        modelerData={modelerData||{}}
        constraint={constraint} 
        template={template}
        validateReports={validateReports}
        supportedDatatypes={supportedDatatypes} 
        onChange={onTableChange} 
        editable={action!=='detail'&&action!=='flow'&&action!=='detail-version'}
        action={action} 
        originAction={getQueryParam(Action, props?.location?.search)}
        terms={terms}
      /> 
      <ImportActionIndex 
        modelerData={modelerData||{}} 
        constraint={constraint} 
        template={template}
        types={supportedIndextypes}
        validateReports={validateReports}
        onChange={onIndexChange} 
        editable={action!=='detail'&&action!=='flow'&&action!=='detail-version'} 
        terms={terms}
      />
    </Spin>
  );
};

export default ImportAction;