package cn.ibizlab.codegen.model;


import cn.ibizlab.codegen.CodegenConfig;
import cn.ibizlab.codegen.CodegenConstants;

import cn.ibizlab.codegen.templating.TemplateFileType;
import cn.ibizlab.codegen.utils.StringAdvUtils;
import net.ibizsys.model.IPSSystem;
import net.ibizsys.model.PSModelServiceImpl;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;


public class ModelStorage {

    public static String USER_HOME = Paths.get(System.getProperty("user.home"), ".ibizlab").toString();


    private static ModelStorage instance = null;

    public static ModelStorage getInstance() {
        if (instance == null)
            instance = new ModelStorage();
        return instance;
    }

    private CodegenConfig config;

    public ModelStorage config(CodegenConfig config) {
        this.config = config;
        return this;
    }


    private SystemModel systemModel = null;

    public SystemModel getSystemModel() {
        if (systemModel == null) {
            String modelPath = config.getInputSpec();
            String strPSModelFolderPath = null;
            if (Files.exists(Paths.get(modelPath, "PSSYSTEM.json"))) {
                strPSModelFolderPath = Paths.get(modelPath).toString();
            } else if (Files.exists(Paths.get(modelPath, "model", "PSSYSTEM.json"))) {
                strPSModelFolderPath = Paths.get(modelPath, "model").toString();
            }


            Assert.hasLength(strPSModelFolderPath, "加载系统模型错误,未找到对应模型目录");

            PSModelServiceImpl psModelService = new PSModelServiceImpl();
            psModelService.setPSModelFolderPath(strPSModelFolderPath);
            try {
                IPSSystem iPSSystem = psModelService.getPSSystem();
                systemModel = new SystemModel(iPSSystem);
                Assert.notNull(iPSSystem, "加载系统模型错误:" + strPSModelFolderPath);
                if (!StringUtils.isEmpty(config.getAdditionalProperties().get(CodegenConstants.PROJECT_NAME)))
                    systemModel.setProjectName(config.getAdditionalProperties().get(CodegenConstants.PROJECT_NAME).toString());
                if (!StringUtils.isEmpty(config.getAdditionalProperties().get(CodegenConstants.PROJECT_DESC)))
                    systemModel.setProjectDesc(config.getAdditionalProperties().get(CodegenConstants.PROJECT_DESC).toString());
                if (!StringUtils.isEmpty(config.getAdditionalProperties().get(CodegenConstants.PACKAGE_NAME)))
                    systemModel.setPackageName(config.getAdditionalProperties().get(CodegenConstants.PACKAGE_NAME).toString());

            } catch (Exception e) {
                throw new RuntimeException("加载系统模型错误" + strPSModelFolderPath, e);
            }

        }
        return systemModel;
    }


    public CliOption newCliOption(TemplateFileType type) {
        CliOption opt = new CliOption();
        opt.putAll(config.getAdditionalProperties());
        opt.setTemplateFileType(type);
        SystemModel systemModel = getSystemModel();
        opt.setProjectName(systemModel.getProjectName());
        opt.setProjectDesc(systemModel.getProjectDesc());
        opt.setPackageName(systemModel.getPackageName());
        opt.set("system", systemModel);
        return opt;
    }


    private Map<TemplateFileType, CliData> templateData = new HashMap<>();

    public CliData getTemplateData(TemplateFileType type) {
        if (!templateData.containsKey(type)) {
            CliData rt = new CliData();
            if (type.equals(TemplateFileType.api)) {

                getSystemModel().getApis().forEach(item -> {
                    CliOption opt = newCliOption(TemplateFileType.api).baseData(item, item.getCodeName().toLowerCase());
                    rt.addOption(opt);
                });

            } else if (type.equals(TemplateFileType.apiEntity)) {
                getSystemModel().getApis().forEach(api -> {
                    api.getApiEntities().forEach(item -> {
                        CliOption opt = newCliOption(TemplateFileType.apiEntity).baseData(item, item.getCodeName().toString()).set("apis", api.getCodeName().toLowerCase());
                        rt.addOption(opt);
                    });
                });
            } else if (type.equals(TemplateFileType.apiDto)) {
                getSystemModel().getApis().forEach(api -> {
                    api.getApiEntities().forEach(item -> {
                        item.getDtos().forEach(dto -> {
                            CliOption opt = newCliOption(TemplateFileType.apiDto)
                                    .setCliSubType(dto.getType())
                                    .baseData(dto, dto.getCodeName())
                                    .set("apiDtos", dto.getCodeName()).set("apis", dto.getApi().getCodeName().toLowerCase()).set("modules",item.getEntity().getModule());
                            rt.addOption(opt);
                        });
                    });
                });
            }
            else if(type.equals(TemplateFileType.app))
            {
                getSystemModel().getApps().forEach(item->{
                    CliOption opt=newCliOption(TemplateFileType.app).baseData(item,item.getCodeName().toLowerCase());
                    rt.addOption(opt);
                });
            }
            else if(type.equals(TemplateFileType.appEntity))
            {
                getSystemModel().getApps().forEach(app->{
                    app.getAppEntities().forEach(item->{
                        CliOption opt=newCliOption(TemplateFileType.appEntity).baseData(item, StringAdvUtils.spinalcase(item.getCodeName())).set("apps",app.getCodeName().toLowerCase());
                        rt.addOption(opt);
                    });
                });
            }
            else if (type.equals(TemplateFileType.entity)) {
                getSystemModel().getEntities().forEach(item -> {
                    CliOption opt = newCliOption(TemplateFileType.entity).setCliSubType(item.getStorage()).setModule(item.getModule())
                            .baseData(item, item.getCodeName().toString());
                    rt.addOption(opt);
                });
            }
            else if (type.equals(TemplateFileType.workflow)) {
                getSystemModel().getWorkflows().forEach(item -> {

                    CliOption opt = newCliOption(TemplateFileType.workflow)
                            .baseData(item, item.getCodeName().toString())
                            .set("wf",item.getWFVer().getWFCodeName());
                    rt.addOption(opt);
                });
            }
            else if (type.equals(TemplateFileType.sysUtil)) {
                getSystemModel().getSysUtils().forEach(item -> {
                    CliOption opt = newCliOption(TemplateFileType.sysUtil)
                            .baseData(item, item.getCodeName().toString());
                    rt.addOption(opt);
                });
            }
//            else if (type.equals(TemplateFileType.subService)) {
//                getSystemModel().getSubServiceApi().forEach(item -> {
//                    CliOption opt = newCliOption(TemplateFileType.subService)
//                            .baseData(item, item.getCodeName().toString());
//                    rt.addOption(opt);
//                });
//            }
//            else if (type.equals(TemplateFileType.subEntity)) {
//                getSystemModel().getSubServiceApi().forEach(item -> {
//                    item.getSubEntityApis().forEach(subEntityApi -> {
//                        CliOption opt = newCliOption(TemplateFileType.subEntity)
//                                .baseData(item, item.getCodeName().toString());
//                        rt.addOption(opt);
//                    });
//                });
//            }
            else if (type.equals(TemplateFileType.module)) {
                getSystemModel().getSystem().getAllPSSystemModules().forEach(item -> {
                    BaseModel model=new BaseModel();
                    model.setCodeName(item.getCodeName());
                    model.setName(item.getName());
                    model.setOpt(item);
                    CliOption opt = newCliOption(TemplateFileType.module)
                            .baseData(model, item.getCodeName());
                    rt.addOption(opt);
                });
            }
            else if(type.equals(TemplateFileType.page))
            {
                getSystemModel().getApps().forEach(app->{
                    app.getPages().forEach(item->{
                        CliOption opt=newCliOption(TemplateFileType.page).setCliSubType(item.getAppView().getViewType()).baseData(item,StringAdvUtils.spinalcase(item.getCodeName())).set("apps",app.getCodeName().toLowerCase()).set("appModules",item.getAppModule().toSpinalCase());

                        rt.addOption(opt);
                    });
                });
            }
            else if(type.equals(TemplateFileType.ctrl))
            {
                getSystemModel().getApps().forEach(app->{
                    app.getCtrls().forEach(item->{
                        if (!item.ignore()) {
                            CliOption opt=newCliOption(TemplateFileType.ctrl).setCliSubType(item.getTempFilter().toUpperCase()).baseData(item,StringAdvUtils.spinalcase(item.getCodeName())).set("apps",app.getCodeName().toLowerCase()).set("appEntities",item.getFolder().toSpinalCase());
                            rt.addOption(opt);
                        }
                    });
                });
            }
            else if (type.equals(TemplateFileType.supportingFiles)) {
                CliOption opt = newCliOption(TemplateFileType.supportingFiles)
                        .set(TemplateFileType.app.value(), getTemplateData(TemplateFileType.app).getOptions())
                        .set(TemplateFileType.api.value(), getTemplateData(TemplateFileType.api).getOptions())
                        .set(TemplateFileType.module.value(), getTemplateData(TemplateFileType.module).getOptions());

                rt.addOption(opt);
            }
            templateData.put(type, rt);
        }
        return templateData.get(type);
    }


}
