package cn.ibizlab.core.lite.extensions.service;

import cn.ibizlab.core.lite.domain.*;
import cn.ibizlab.core.lite.extensions.domain.MetaEntityModel;
import cn.ibizlab.core.lite.extensions.domain.SysModel;
import cn.ibizlab.core.lite.extensions.mapping.MetaEntityMapping;
import cn.ibizlab.core.lite.filter.MetaFieldSearchContext;
import cn.ibizlab.core.lite.service.*;
import cn.ibizlab.util.errors.BadRequestAlertException;
import cn.ibizlab.util.helper.DataObject;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.*;

@Service
@Slf4j
public class LiteCoreService {

    public final static int ONLYCREATE=1;
    public final static int ONLYUPDATE=2;
    public final static int CREATEORUPDATE=3;


    @Autowired
    @Lazy
    IMetaEntityService entityService;

    @Autowired
    @Lazy
    IMetaFieldService fieldService;

    @Autowired
    @Lazy
    IMetaRelationshipService relationService;

    @Autowired
    @Lazy
    LiteCoreService proxyService;

    @Autowired
    @Lazy
    MetaEntityMapping entityMapping;

    @Autowired
    @Lazy
    IMetaModuleService moduleService;

    @Autowired
    @Lazy
    IDstDataSourceService dataSourceService;

    @Transactional
    public boolean syncSysModel(SysModel sysModel) {
        proxyService.asyncSysModel(sysModel,CREATEORUPDATE);
        return true;
    }

    @Transactional
    public boolean syncSysModel(SysModel sysModel, int saveMode) {
        proxyService.asyncSysModel(sysModel,saveMode);
        return true;
    }

    @Transactional
    @Async("asyncExecutor")
    public void asyncSysModel(SysModel sysModel, int saveMode) {
        long start = System.currentTimeMillis();
        log.info("开始同步[{}]系统模型",sysModel.getSystemid());
        syncDE(sysModel,saveMode);
        syncDEField(sysModel,saveMode);
        syncDERelation(sysModel,saveMode);
        syncDataSource(sysModel);
        long end = System.currentTimeMillis();
        log.info("完成[{}]系统同步模型任务，总耗时[{}]秒",sysModel.getSystemid(),(end-start)/1000);
    }

    /**
     * 初始化master datasource
     * @param sysModel
     */
    private void syncDataSource(SysModel sysModel) {
        DstDataSource dataSource= new DstDataSource();
        dataSource.setDsId(String.format("%s-master",sysModel.getSystemid()));
        dataSource.setDsName(String.format("[%s]主数据源",sysModel.getSystemname()));
        dataSourceService.save(dataSource);
    }

    private Map<String,String> gloabEntity = new HashMap<>();

    /**
     * 同步实体
     * @param sysModel
     */
    private void syncDE(SysModel sysModel, int saveMode) {
        Map<String,String> delDE = new HashMap<>();
        Map<String,Integer> delModule = new HashMap<>();
        entityService.list(new QueryWrapper<MetaEntity>().select("entityid","entityname").eq("systemid",sysModel.getSystemid())).forEach(entity -> delDE.put(entity.getEntityName(),entity.getEntityId()));
        moduleService.list(new QueryWrapper<MetaModule>().select("codename").eq("systemid",sysModel.getSystemid())).forEach(module -> delModule.put(module.getCodeName(),1));
        List<MetaEntityModel> metaEntityModels = sysModel.getEntities();
        Set<MetaEntity> entities=new HashSet<>();
        List<MetaEntity> create=new ArrayList<>();
        List<MetaEntity> update=new ArrayList<>();
        Map<Object, MetaModule> modulesMap = new HashMap<>();
        if(!ObjectUtils.isEmpty(metaEntityModels)){
            entities.addAll(entityMapping.toDomain(metaEntityModels));
        }
        entities.forEach(entity -> {
            if(delDE.containsKey(entity.getEntityName())) {
                entity.setEntityId(delDE.get(entity.getEntityName()));
                update.add(entity);
                delDE.remove(entity.getEntityName());
            }
            else
            {
                entity.setEntityId(entity.getDefaultKey(true).toString());
                create.add(entity);
            }
            gloabEntity.put((sysModel.getSystemid()+"."+entity.getEntityName()).toUpperCase(),entity.getEntityId());
            String moduleId=entity.getModuleId();
            String moduleName=entity.getModuleName();
            if(!ObjectUtils.isEmpty(moduleId) && !ObjectUtils.isEmpty(moduleName)){
                delModule.remove(moduleId);
                if(!modulesMap.containsKey(moduleId)){
                    MetaModule module =new MetaModule();
                    module.setCodeName(moduleId);
                    module.setName(moduleName);
                    module.setSystemId(sysModel.getSystemid());
                    modulesMap.put(moduleId,module);
                }
                MetaModule module = modulesMap.get(moduleId);
                entity.setModuleId(module.getId());
                entity.setModuleName(module.getName());
                entity.setModule(module);
            }
        });
        //移除无效资源
//        if(delDE.size()>0)
//            entityService.removeBatch(delDE.values());
//        if(delModule.size()>0)
//            moduleService.removeBatch(delModule.keySet());
        //存储或更新资源saveOrUpdate

        if(modulesMap.size()>0)
            moduleService.saveBatch(modulesMap.values());
        if(create.size()>0&&saveMode!=ONLYUPDATE)
            entityService.createBatch(create);
        if(update.size()>0&&saveMode!=ONLYCREATE)
            entityService.updateBatch(update);
    }

    /**
     * 同步实体属性
     * @param sysModel
     */
    private void syncDEField(SysModel sysModel, int saveMode) {
        Map<String, MetaField> delField = new HashMap<>();


        MetaFieldSearchContext context=new MetaFieldSearchContext();
        context.setSize(Integer.MAX_VALUE);
        context.setN_systemid_eq(sysModel.getSystemid());
        fieldService.searchDefault(context).getContent().forEach(item->{
            delField.put((item.getEntityName()+"."+item.getFieldName()).toUpperCase(),item);
        });

        List<MetaField> create=new ArrayList<>();
        List<MetaField> update=new ArrayList<>();
        List<MetaField> change=new ArrayList<>();
        Set<MetaField> list = sysModel.getField();
        list.forEach(field -> {
            if(gloabEntity.containsKey((sysModel.getSystemid()+"."+field.getEntityName()).toUpperCase()))
                field.setEntityId(gloabEntity.get((sysModel.getSystemid()+"."+field.getEntityName()).toUpperCase()));
            String fieldKey=(field.getEntityName()+"."+field.getFieldName()).toUpperCase();
            if(delField.containsKey(fieldKey))
            {
                MetaField oldField = delField.get(fieldKey);
                field.setFieldId(oldField.getFieldId());
                update.add(field);

                if((!DataObject.getStringValue(oldField.getFieldType(),"").equalsIgnoreCase(DataObject.getStringValue(field.getFieldType(),"")))
                        ||(DataObject.getIntegerValue(oldField.getDataLength(),0)!= DataObject.getIntegerValue(field.getDataLength(),0)&&(!DataObject.getStringValue(oldField.getFieldType(),"").startsWith("DATE")))
                        || DataObject.getIntegerValue(oldField.getNullable(),0)!= DataObject.getIntegerValue(field.getNullable(),0)
                        ||(!DataObject.getStringValue(oldField.getUnionKey(),"").equalsIgnoreCase(DataObject.getStringValue(field.getUnionKey(),"")))
                        ||(DataObject.getIntegerValue(oldField.getKeyField(),0)!= DataObject.getIntegerValue(field.getKeyField(),0))
                        ||(!DataObject.getStringValue(oldField.getPredefined(),"").equalsIgnoreCase(DataObject.getStringValue(field.getPredefined(),"")))
                        ||((!DataObject.getStringValue(oldField.getExpression(),"").equalsIgnoreCase(DataObject.getStringValue(field.getExpression(),"")))&& DataObject.getIntegerValue(oldField.getPhysicalField(),1)==0)
                )
                {
                    MetaField newField=new MetaField();
                    newField.setFieldId(oldField.getFieldId());
                    newField.setEntityName(field.getEntityName());
                    newField.setFieldName(field.getFieldName());
                    newField.setDataType(field.getDataType());
                    newField.setFieldType(field.getFieldType());
                    newField.setDataLength(field.getDataLength());
                    newField.setDataPreci(field.getDataPreci());
                    newField.setNullable(field.getNullable());
                    newField.setUnionKey(field.getUnionKey());
                    if(!StringUtils.isEmpty(field.getExpression()))
                        newField.setExpression(field.getExpression());
                    if(!StringUtils.isEmpty(field.getPredefined()))
                        newField.setPredefined(field.getPredefined());
                    newField.setKeyField(field.getKeyField());
                    change.add(newField);
                }


                delField.remove(fieldKey);

            }
            else {
                field.setFieldId(field.getDefaultKey(true).toString());
                create.add(field);
            }

        });
        //移除无效资源
//        if(delField.size()>0)
//            fieldService.removeBatch(delField.values());
        //存储或更新资源saveOrUpdate

        change.forEach(newField->{
            System.out.println(newField.getEntityName()+"."+newField.getFieldName()+" "+newField.getDataType()+"("+newField.getDataLength()+(DataObject.getIntegerValue(newField.getDataPreci(),0)==0?")":(","+newField.getDataPreci()+")"))
                    +(DataObject.getIntegerValue(newField.getNullable(),0)==0?" not null":" null")+" "+ DataObject.getStringValue(newField.getUnionKey(),""));
        });

        if(create.size()>0&&saveMode!=ONLYUPDATE) {
            fieldService.createBatch(create);
        }
        if(change.size()>0&&saveMode==ONLYCREATE) {
            fieldService.updateBatch(change);
        }
        if(update.size()>0&&saveMode!=ONLYCREATE) {
            fieldService.updateBatch(update);
        }
    }

    /**
     * 同步实体关系
     * @param sysModel
     */
    private void syncDERelation(SysModel sysModel, int saveMode) {
        Map<String,Integer> delRelation = new HashMap<>();
        Map param=new HashMap();
        param.put("id",sysModel.getSystemid());
        List<JSONObject> oldRelation=relationService.select("select distinct(relationid) from ibzrelation t inner join ibzentity t1 on t.entityid=t1.entityid or t.refentityid=t1.entityid where t1.systemid=#{et.id} ",param);
        for(JSONObject relation: oldRelation){
            delRelation.put(relation.getString("RELATIONID"),1);
        }
        List<MetaRelationship> create=new ArrayList<>();
        List<MetaRelationship> update=new ArrayList<>();

        Collection<MetaRelationship> list = sysModel.getRelation();
        list.forEach(relation -> {
            if(delRelation.containsKey(relation.getId()))
            {
                delRelation.remove(relation.getId());
                update.add(relation);
            }
            else
                create.add(relation);

        });
        //移除无效资源
//        if(delRelation.size()>0)
//            relationService.removeBatch(delRelation.keySet());
        //存储或更新资源saveOrUpdate
        if(create.size()>0&&saveMode!=ONLYUPDATE)
            relationService.createBatch(create);
        if(update.size()>0&&saveMode!=ONLYCREATE)
            relationService.updateBatch(update);
    }




}
