import React, { useState, useEffect, useRef, useImperativeHandle } from 'react';
import { Spin, Tabs, Anchor, Affix, Button } from 'antd';
import LocalStorage from 'local-storage';
import { Subject } from 'rxjs'

import ImportActionHeader from './ImportActionHeader'; 
import { ImportActionTable } from './ImportActionTable';
import ImportActionIndex from './ImportActionIndex';
import ImportActionManage from './ImportActionManage';
import ImportActionRelation from './ImportActionRelation';
import ImportActionComment from './ImportActionComment';
import { getInternalCurrentAnchor, getQueryParam } from '../../../../util';
import { Action } from '../../../../util/constant';
import { dispatch } from '../../../../model'; 

import './ImportAction.less'
import ImportActionProcess from './ImportActionProcess';

export const ImportActionSubject = new Subject();

const ImportAction = React.forwardRef((props, ref) => {
  const { action, hints, onChange, form, modelerId, terms, ddl, roughModelerData, versionId, permitCheckOut, catalogId, logicId, metadataId } = 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 [container, setContainer] = useState();
  const [activeValue, setActiveValue] = useState();

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

  useImperativeHandle(ref, () => ({
    isLoading: () => {
      return loading;
    }
  }), [loading])

  const onTabChange = (val) => {
    setActiveValue(val);
    var targetElement = container?.querySelector(`.${val}`); // 找到目标元素
    if (targetElement) {
      animating.current = true;
      targetElement.scrollIntoView();
    }
  }

  useEffect(() => {
    const $$action = ImportActionSubject.subscribe((act) => {
      if (act?.type === 'tabChangeEvent' && act?.key) {
        onTabChange(act?.key)
      } 
    })
    return () => {
      $$action.unsubscribe()
    }
  }, [onTabChange])

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

    if ((!mountRef.current && action === 'edit' && !permitCheckOut) || action === 'edit-inherited') {
      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.getAllConstraints',
      callback: data => {
        setConstraints(data);
        if (action === 'add') {
          // setConstraint(data?.length>0?data[0]:{});
          // setTemplate({});
          if (logicId) {
            conceptualModelCreateDataModel()
          } else if ((hints||[]).length>0) {
            getDraft(data?.length>0?data[0]:{}, {} ,hints);
          } else if ((ddl||'').length>0) {
            getDraftUsingDDL(data?.length>0?data[0]:{}, {} ,ddl);
          } else if (metadataId) {
            getDraftUsingMetadataId(data?.length>0?data[0]:{}, {} ,metadataId);
          } else if ((modelerId||'')!=='') {
            getCurrentDataModel();
          } else if (roughModelerData) {
            setLoading(false);
            getExtraData(roughModelerData);
          } else {
            getDraft(data?.length>0?data[0]:{}, {} ,[]);
          }
        } else if(action === 'edit' || action === 'detail' || action ==='flow' || action === 'detail-version') {
          getCurrentDataModel();
        } else if (action === 'edit-inherite-modal') {
          setLoading(false);
          getExtraData(roughModelerData);
        }
      },
      error: () => {
        setLoading(false);
      }
    })
 
    //eslint-disable-next-line react-hooks/exhaustive-deps
  }, [action, hints, modelerId, ddl ]);

  useEffect(() => {
    if (constraint?.name) {
      getTemplates();
    } else {
      setTemplates([]);
    }
    //eslint-disable-next-line react-hooks/exhaustive-deps
  }, [constraint])

  React.useEffect(() => {
    if (container) {
      handleScroll();
      container?.addEventListener('scroll', handleScroll);
      return () => {
        container?.removeEventListener('scroll', handleScroll);
      };
    }
  }, [container]);

  const handleScroll = React.useCallback(() => {
    if (animating.current) {
      animating.current = false;
      return;
    }

    const currentActiveLink = getInternalCurrentAnchor(
      [
        'model-import-action-basic',
        'model-import-action-technical',
        'model-import-action-table',
        'model-import-action-index',
        'model-import-action-process',
        'model-import-action-manage',
        // 'model-import-action-relation',
        'model-import-action-comment',
      ],
      20,
      5,
      container
    );
    
    setActiveValue(currentActiveLink)
  }, [container]);

  const getTemplates = () => {
    dispatch({
      type: 'datamodel.getAllTemplates',
      payload: {
        constraintName: constraint.name
      },
      callback: data => {
        setTemplates(data);
      }
    }) 
  }

  const conceptualModelCreateDataModel = () => { 
    dispatch({
      type: 'datamodel.conceptualModelCreateDataModel',
      payload: {
        data: [logicId]  
      },
      callback: data => {
        setLoading(false);
        if ((data??[]).length > 0) {
          getExtraData(data[0]);
        }
      },
      error: () => {
        setLoading(false);
      }
    })
  }

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

  const getDraftUsingMetadataId = (_constraint, _template, _metadataId) => { 
    dispatch({
      type: 'datamodel.getDraftUsingMetadataId',
      payload: {
        params: {
          dataCatalogId: catalogId,
        },
        data: {
          metadataTableId: _metadataId,
          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);

      }, 
      error: () => {
        form.setFieldsValue({ 
          easyDataModelerModelingTemplate: modelerDataRef.current.easyDataModelerModelingTemplate,
          tableType: modelerDataRef.current.tableType
        });

        setTemplate(modelerDataRef.current.easyDataModelerModelingTemplate);
      }
    })
  }

  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;
    
    const index = (constraints??[]).findIndex(item => item.id === value)
    if (index !== -1) {
      currentConstraint = constraints[index]
      form.setFieldsValue({ 
        easyDataModelerModelingConstraint: currentConstraint
      });
      const newModelerData = {...modelerData, easyDataModelerModelingConstraint: currentConstraint };
      setModelerData(newModelerData);
      modelerDataRef.current = newModelerData;
  
      onChange && onChange(newModelerData);
  
      setConstraint(currentConstraint);
      getConsult(newModelerData);
    }
  }

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

    const newModelerData = {...modelerData, easyDataModelerModelingTemplate: currentTemplate, tableType: currentTemplate ? currentTemplate.cnName : value };

    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 onProcessChange = (data, validate=false) => {
    const newModelerData = {...modelerDataRef.current, processingList: data};

    setModelerData(newModelerData);
    modelerDataRef.current = newModelerData;

    onChange && onChange(newModelerData);

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

  const getConsistentKeys = (newModelerData) => {

    //分布键
    let newDistribution = {...newModelerData.distributionKey};

    newDistribution.keys = (newDistribution.keys??[]).filter(item => (newModelerData.easyDataModelerDataModelAttributes??[]).findIndex(_item => item.iid === _item.iid) !== -1)

     //主键
     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||{})};

    if (newModelerData.dbType === 'Hive') {
      newPartition.keys = (newPartition.keys??[]).filter(item => (newModelerData.easyDataModelerDataModelAttributes??[]).findIndex(_item => item.name === _item.name) === -1)
    } else {
      newPartition.keys = (newPartition.keys??[]).filter(item => (newModelerData.easyDataModelerDataModelAttributes??[]).findIndex(_item => item.iid === _item.iid) !== -1)
    }

    if ((newPartition.keys||[]).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, distributionKey: newDistribution, easyDataModelerPrimaryKey: newPrimary, easyDataModelerIndices: newEasyDataModelerIndices, easyDataModelerSemiPrimaryKey: newSemiPrimary};
  }

  return (
    <Spin spinning={loading}>
      {
        (action==='detail' && ((modelerData||{}).optionList||[]).findIndex(item => item.enabled && item.name==='查看') === -1) ? <div style={{ padding: '10px 20px', height: 60 }}>
          {loading?'':'暂无权限'}
        </div> : <div className='import-action'>
          <Tabs activeKey={activeValue} centered onChange={onTabChange}>
            <Tabs.TabPane tab='基本信息' key="model-import-action-basic" />
            <Tabs.TabPane tab='技术信息' key="model-import-action-technical" />
            <Tabs.TabPane tab='数据表结构' key="model-import-action-table" />
            <Tabs.TabPane tab='数据表索引' key="model-import-action-index" />
            <Tabs.TabPane tab='加工步骤' key="model-import-action-process" />
            <Tabs.TabPane tab='管理信息' key="model-import-action-manage" />
            {/* <Tabs.TabPane tab='关联对象' key="model-import-action-relation" /> */}
            {
              modelerData?.id && <Tabs.TabPane tab='模型评论' key="model-import-action-comment" />
            }
          </Tabs>
          <div ref={setContainer} style={{ height: action==='edit-inherite-modal'?'60vh':'calc(100vh - 44px - 64px - 66px)', overflow: 'auto', padding: '20px 20px 0' }}>
            <ImportActionHeader 
              form={form}
              editable={action!=='detail'&&action!=='flow'&&action!=='detail-version'&&action!=='edit-inherited'} 
              modelerData={modelerData||{}} 
              constraints={constraints}
              templates={templates}
              validateReports={validateReports}
              onTemplateChange={onTemplateChange}
              onConstraintChange={onConstraintChange}
              onChange={onHeaderChange}
              terms={terms}
              supportedPartitionTypes={supportedPartitionTypes} 
              catalogId={catalogId}
            />   
            <ImportActionTable 
              modelerData={modelerData||{}}
              constraint={constraint} 
              template={template}
              validateReports={validateReports}
              supportedDatatypes={supportedDatatypes} 
              onChange={onTableChange} 
              editable={action!=='detail'&&action!=='flow'&&action!=='detail-version'&&action!=='edit-inherited'}
              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'&&action!=='edit-inherited'} 
              terms={terms}
            />
            <ImportActionProcess 
              modelerData={modelerData||{}} 
              constraint={constraint} 
              template={template}
              onChange={onProcessChange} 
              editable={action!=='detail'&&action!=='flow'&&action!=='detail-version'&&action!=='edit-inherited'} 
              terms={terms}
            />
            <ImportActionManage
              form={form}
              modelerData={modelerData||{}} 
              editable={action!=='detail'&&action!=='flow'&&action!=='detail-version'&&action!=='edit-inherited'} 
            />
            {/* <ImportActionRelation
              modelerData={modelerData} action={action} 
            /> */}
            {
              modelerData?.id && <ImportActionComment
              modelerData={modelerData}
            />
            }
          </div>
        </div>
      }
    </Spin>
  );
});

export default ImportAction;