package cn.ibizlab.codegen.model;

import cn.ibizlab.codegen.templating.TemplateFileType;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import net.ibizsys.model.IPSSystem;
import net.ibizsys.model.codelist.IPSCodeList;
import net.ibizsys.model.database.IPSDEFDTColumn;
import net.ibizsys.model.dataentity.IPSDataEntity;
import net.ibizsys.model.dataentity.defield.IPSDEField;
import net.ibizsys.model.dataentity.defield.IPSLinkDEField;
import net.ibizsys.model.dataentity.der.IPSDER1N;
import net.ibizsys.model.dataentity.der.IPSDERBase;
import net.ibizsys.model.dataentity.ds.IPSDEDataQueryCode;
import net.ibizsys.model.dataentity.ds.IPSDEDataQueryCodeCond;
import net.ibizsys.model.dataentity.ds.IPSDEDataSetGroupParam;
import net.ibizsys.model.dataentity.ds.PSDEDataSetGroupParamImpl;
import net.ibizsys.model.pub.IPSSysSFPub;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
public class SystemModel extends BaseModel {

    public SystemModel(IPSSystem system) {
        this.opt = system;
        system.getAllPSSystemModules().forEach(item -> {

        });
        if (!ObjectUtils.isEmpty(system.getAllPSSysSFPubs())) {
            system.getAllPSSysSFPubs().forEach(pub -> {
                if (pub.isMainPSSysSFPub())
                    this.pub = pub;
            });

            if (this.pub == null)
                this.pub = system.getAllPSSysSFPubs().get(0);
        }
        if (this.pub != null) {
            this.setCodeName(this.pub.getCodeName());
            this.setName(this.pub.getName());
            this.setProjectName(this.pub.getCodeName().toLowerCase());
            this.setProjectDesc(this.pub.getName());
            this.setPackageName(this.pub.getPKGCodeName());
        } else {
            this.setCodeName(system.getCodeName());
            this.setName(system.getName());
            this.setProjectName(system.getCodeName().toLowerCase());
            this.setProjectDesc(system.getName());
            this.setPackageName(system.getCodeName().toLowerCase());
        }
        getEntitiesMap();
    }

    public IPSSystem getSystem() {
        return (IPSSystem) opt;
    }

    private String projectName;

    private String projectDesc;

    private String packageName;

    private boolean enableDS = false;
    private boolean enableES = false;
    private boolean enableMongo = false;
    private boolean enableMQ = false;
    private boolean enableOAuth2 = false;
    private boolean enableGlobalTransaction = false;
    private boolean enableMysql = false;
    private boolean enableOracle = false;
    private boolean enableDameng = false;
    private boolean enablePostgreSQL = false;
    private boolean enableDyna = false;
    private boolean enableWorkflow = false;

    private IPSSysSFPub pub;

    private Set<String> mqSubscribes;


    private Map<String, EntityModel> entitiesMap;

    public synchronized Map<String, EntityModel> getEntitiesMap() {
        if (entitiesMap == null) {
            entitiesMap = new LinkedHashMap<>();
            getSystem().getAllPSDataEntities().forEach(entity -> {
                if ((entity.getStorageMode() == 1 || entity.getStorageMode() == 2) && "DEFAULT".equals(entity.getDSLink()))
                    enableDS = true;
                if (entity.getStorageMode() == 2)
                    enableMongo = true;
                if (ObjectUtils.isEmpty(entity.getAllPSDEWFs()))
                    enableWorkflow = true;
                if (!enableES && "elasticsearch".equalsIgnoreCase(entity.getUserTag()))
                    enableES = true;
                if (!enableMQ && !ObjectUtils.isEmpty(entity.getAllPSDEDataSyncs()))
                    enableMQ = true;
                if (entity.getAllPSDEDataSyncs() != null) {
                    entity.getAllPSDEDataSyncs().forEach(sync -> {
                        if (sync.getInPSSysDataSyncAgent() != null) {
                            if (mqSubscribes == null) mqSubscribes = new LinkedHashSet<>();
                            mqSubscribes.add(sync.getCodeName());
                        }
                    });
                }
                entitiesMap.put(entity.getCodeName(), new EntityModel(this, entity));
            });
        }
        return entitiesMap;
    }

    private Map<String, WorkflowModel> workflowsMap;

    public synchronized Map<String, WorkflowModel> getWorkflowsMap() {
        if (workflowsMap == null) {
            try {
                workflowsMap = new LinkedHashMap<>();
                getSystem().getAllPSWorkflows().forEach(workflow -> {
                    workflow.getPSWFVersions().forEach(workflowVersion -> {
                        workflowsMap.put(workflowVersion.getCodeName(), new WorkflowModel(this, workflow,workflowVersion));
                    });
                });
            } catch (Exception e) {

            }
        }
        return workflowsMap;
    }

    public Collection<WorkflowModel> getWorkflows() {
        return getWorkflowsMap().values();
    }

    private Map<String, SysUtilModel> sysUtilModelMap;

    public synchronized Map<String, SysUtilModel> getSysUtilModelMaps() {
        if (sysUtilModelMap == null) {
            try {
                sysUtilModelMap = new LinkedHashMap<>();
                getSystem().getAllPSSysUtils().forEach(iPSSysUtil -> {
                    sysUtilModelMap.put(iPSSysUtil.getCodeName(), new SysUtilModel(iPSSysUtil));
                });
            } catch (Exception e) {

            }
        }
        return sysUtilModelMap;
    }

    public Collection<SysUtilModel> getSysUtils() {
        return getSysUtilModelMaps().values();
    }

    public boolean isHasMsgTemplate() {
        return !ObjectUtils.isEmpty(getSystem().getAllPSSysMsgTempls());
    }

    public boolean isHasRuntimeDict() {
        if (getSystem().getAllPSCodeLists() != null) {
            for (IPSCodeList dict : getSystem().getAllPSCodeLists()) {
                if ("RUNTIME".equalsIgnoreCase(dict.getPredefinedType()))
                    return true;
            }
        }
        return false;
    }

    public Collection<EntityModel> getEntities() {
        return getEntitiesMap().values();
    }

    private Map<String, AppModel> appsMap;

    public synchronized Map<String, AppModel> getAppsMap() {
        if (appsMap == null) {
            appsMap = new LinkedHashMap<>();
            if (getSystem().getAllPSApps() != null) {
                getSystem().getAllPSApps().forEach(item -> {
                    appsMap.put(item.getCodeName(), new AppModel(item).setSystem(this));
                });
            }
        }
        return appsMap;
    }

    public Collection<AppModel> getApps() {
        return getAppsMap().values();
    }

    private Map<String, ApiModel> apisMap;

    public synchronized Map<String, ApiModel> getApisMap() {
        if (apisMap == null) {
            try {
                apisMap = new LinkedHashMap<>();
                getSystem().getAllPSSysServiceAPIs().forEach(api -> {
                    apisMap.put(api.getCodeName(), new ApiModel(api).setSystem(this));
                });
            } catch (Exception e) {

            }
        }
        return apisMap;
    }

    public Collection<ApiModel> getApis() {
        return getApisMap().values();
    }

    private Map<String, SubServiceApiModel> subServiceApiMap;

    public synchronized Map<String, SubServiceApiModel> getSubServiceApiMap() {
        if (subServiceApiMap == null) {
            subServiceApiMap = new LinkedHashMap<>();
            getSystem().getAllPSSubSysServiceAPIs().forEach(subSysServiceAPI -> {
                subServiceApiMap.put(subSysServiceAPI.getCodeName(), new SubServiceApiModel(subSysServiceAPI).setSystem(this));
            });
        }
        return subServiceApiMap;
    }

    public Collection<SubServiceApiModel> getSubServiceApi() {
        return getSubServiceApiMap().values();
    }


    public EntityModel getEntity(String codeName) {
        return getEntitiesMap().get(codeName);
    }


}
