package com.qiaoba.module.generator.util;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.StrUtil;
import com.qiaoba.common.base.constant.BaseConstant;
import com.qiaoba.common.base.context.BaseContext;
import com.qiaoba.common.base.enums.BaseEnum;
import com.qiaoba.module.generator.constant.GenConstants;
import com.qiaoba.module.generator.entity.Generator;
import com.qiaoba.module.generator.entity.GeneratorTable;
import com.qiaoba.module.generator.entity.GeneratorTableColumn;
import org.apache.commons.lang3.StringUtils;
import org.apache.velocity.VelocityContext;

import java.util.*;

/**
 * 模板生成 工具类
 *
 * @author ailanyin
 * @version 1.0
 * @since 2023/7/3 9:22
 */
public class VelocityUtil {

    private static final List<String> TEMPLATE_JAVA = new ArrayList<>();
    private static final List<String> TEMPLATE_VUE = new ArrayList<>();
    private static final List<String> TEMPLATE_SQL = new ArrayList<>();

    private static final String VM_CONTROLLER = "controller.java.qb";
    private static final String VM_DOMAIN = "entity.java.qb";
    private static final String VM_DTO = "dto.java.qb";
    private static final String VM_PARAM = "param.java.qb";
    private static final String VM_EXCEL_EXPORT = "export.java.qb";
    private static final String VM_MAPPER = "mapper.java.qb";
    private static final String VM_SERVICE = "service.java.qb";
    private static final String VM_SERVICE_IMPL = "serviceImpl.java.qb";
    private static final String VM_SQL = "sql.qb";
    private static final String VM_API_JS = "api.js.qb";
    private static final String VM_INDEX_VUE = "index.qb";

    /**
     * 项目空间路径
     */
    private static final String PROJECT_PATH = "main/java";


    static {
        // 后端
        TEMPLATE_JAVA.add("vm/java/entity.java.qb");
        TEMPLATE_JAVA.add("vm/java/dto.java.qb");
        TEMPLATE_JAVA.add("vm/java/param.java.qb");
        TEMPLATE_JAVA.add("vm/java/export.java.qb");
        TEMPLATE_JAVA.add("vm/java/controller.java.qb");
        TEMPLATE_JAVA.add("vm/java/service.java.qb");
        TEMPLATE_JAVA.add("vm/java/serviceImpl.java.qb");
        TEMPLATE_JAVA.add("vm/java/mapper.java.qb");
        // 前端
        TEMPLATE_VUE.add("vm/js/api.js.qb");
        TEMPLATE_VUE.add("vm/vue/index.qb");
        // SQL
        TEMPLATE_SQL.add("vm/sql/sql.qb");

    }

    /**
     * 加载模板
     *
     * @return 模板集合
     */
    public static List<String> getTemplateList(String templateType) {
        List<String> templates = new ArrayList<>();
        // 全部
        if (GenConstants.TEMPLATE_TYPE_ALL.equals(templateType)) {
            // 后端
            templates.addAll(TEMPLATE_JAVA);
            // 前端
            templates.addAll(TEMPLATE_VUE);
            // SQL
            templates.addAll(TEMPLATE_SQL);

        }
        // 后端
        else if (GenConstants.TEMPLATE_TYPE_JAVA.equals(templateType)) {
            // 后端
            templates.addAll(TEMPLATE_JAVA);
        }
        // 前端
        else if (GenConstants.TEMPLATE_TYPE_VUE.equals(templateType)) {
            // 前端
            templates.addAll(TEMPLATE_VUE);
        } else {
            // SQL
            templates.addAll(TEMPLATE_SQL);
        }
        return templates;
    }

    public static VelocityContext setVariables(Generator generator) {

        String moduleName = generator.getTable().getModuleName();
        String businessName = generator.getTable().getBusinessName();
        String packageName = generator.getTable().getPackageName();
        String functionName = generator.getTable().getFunctionName();

        VelocityContext velocityContext = new VelocityContext();
        velocityContext.put("tableName" , generator.getTable().getTableName());
        velocityContext.put("functionName" , StrUtil.isNotBlank(functionName) ? functionName : "【请填写功能名称】");
        velocityContext.put("ClassName" , generator.getTable().getClassName());
        velocityContext.put("className" , StringUtils.uncapitalize(generator.getTable().getClassName()));
        velocityContext.put("moduleName" , generator.getTable().getModuleName());
        velocityContext.put("BusinessName" , StringUtils.capitalize(generator.getTable().getBusinessName()));
        velocityContext.put("businessName" , generator.getTable().getBusinessName());
        velocityContext.put("basePackage" , getPackagePrefix(packageName));
        velocityContext.put("packageName" , packageName);
        velocityContext.put("author" , generator.getTable().getAuthor());
        velocityContext.put("docFlag" , BaseEnum.YES.getCode().equals(generator.getTable().getDocFlag()));
        velocityContext.put("excelFlag" , BaseEnum.YES.getCode().equals(generator.getTable().getExcelFlag()));
        velocityContext.put("datetime" , DateUtil.now());
        velocityContext.put("pkColumn" , generator.getPkColumn());

        velocityContext.put("permissionPrefix" , getPermissionPrefix(moduleName, businessName));
        velocityContext.put("columns" , generator.getColumns());
        velocityContext.put("queryColumns" , generator.getQueryColumns());
        velocityContext.put("table" , generator.getTable());
        velocityContext.put("generator" , generator);

        velocityContext.put("dicts" , getDict(generator.getColumns()));

        String parentId = new Snowflake().nextIdStr();
        velocityContext.put("parentId" , parentId);
        velocityContext.put("insertMenuId" , new Snowflake().nextIdStr());
        velocityContext.put("updateMenuId" , new Snowflake().nextIdStr());
        velocityContext.put("deleteMenuId" , new Snowflake().nextIdStr());
        velocityContext.put("selectMenuId" , new Snowflake().nextIdStr());
        velocityContext.put("exportMenuId" , new Snowflake().nextIdStr());

        velocityContext.put("tenantId" , BaseContext.getTenantId());

        String parentMenuId = generator.getTable().getParentMenuId();
        velocityContext.put("parentMenuId" , StrUtil.isNotBlank(parentMenuId) ? parentMenuId : BaseConstant.DEFAULT_PARENT_ID_VALUE);

        return velocityContext;
    }

    /**
     * 获取包前缀
     *
     * @param packageName 包名称
     * @return 包前缀名称
     */
    private static String getPackagePrefix(String packageName) {
        int lastIndex = packageName.lastIndexOf(".");
        return StringUtils.substring(packageName, 0, lastIndex);
    }

    /**
     * 获取权限前缀
     *
     * @param moduleName   模块名称
     * @param businessName 业务名称
     * @return 返回权限前缀
     */
    private static String getPermissionPrefix(String moduleName, String businessName) {
        return StrUtil.format("{}:{}" , moduleName, businessName);
    }

    /**
     * 根据列类型获取字典组
     *
     * @param columns columns
     * @return 返回字典组
     */
    private static String getDict(List<GeneratorTableColumn> columns) {

        Set<String> dictSet = new HashSet<String>();
        addDictList(dictSet, columns);
        return StringUtils.join(dictSet, ", ");
    }

    /**
     * 添加字典列表
     *
     * @param dictSet 字典列表
     * @param columns 列集合
     */
    private static void addDictList(Set<String> dictSet, List<GeneratorTableColumn> columns) {
        for (GeneratorTableColumn column : columns) {
            if (StrUtil.isNotBlank(column.getDictType()) && StringUtils.equalsAny(
                    column.getHtmlType(),
                    new String[]{GenConstants.HTML_SELECT, GenConstants.HTML_RADIO, GenConstants.HTML_CHECKBOX})) {
                dictSet.add("'" + column.getDictType() + "'");
            }
        }
    }

    /**
     * 获取文件名
     */
    public static String getFileName(String template, GeneratorTable genTable) {
        // 文件名称
        String fileName = "";
        // 包路径
        String packageName = genTable.getPackageName();
        // 模块名
        String moduleName = genTable.getModuleName();
        // 大写类名
        String className = genTable.getClassName();
        // 业务名称
        String businessName = genTable.getBusinessName();

        String javaPath = PROJECT_PATH + "/" + StrUtil.replace(packageName, "." , "/");
        String vuePath = "vue";

        if (template.contains(VM_DOMAIN)) {
            fileName = StrUtil.format("{}/entity/{}.java" , javaPath, className);
        } else if (template.contains(VM_DTO)) {
            fileName = StrUtil.format("{}/entity/dto/{}Dto.java" , javaPath, className);
        } else if (template.contains(VM_EXCEL_EXPORT)) {
            fileName = StrUtil.format("{}/entity/template/{}Export.java" , javaPath, className);
        } else if (template.contains(VM_PARAM)) {
            fileName = StrUtil.format("{}/entity/param/{}Param.java" , javaPath, className);
        } else if (template.contains(VM_MAPPER)) {
            fileName = StrUtil.format("{}/mapper/{}Mapper.java" , javaPath, className);
        } else if (template.contains(VM_SERVICE)) {
            fileName = StrUtil.format("{}/service/{}Service.java" , javaPath, className);
        } else if (template.contains(VM_SERVICE_IMPL)) {
            fileName = StrUtil.format("{}/service/impl/{}ServiceImpl.java" , javaPath, className);
        } else if (template.contains(VM_CONTROLLER)) {
            fileName = StrUtil.format("{}/controller/{}Controller.java" , javaPath, className);
        } else if (template.contains(VM_SQL)) {
            fileName = businessName + "Menu.sql";
        } else if (template.contains(VM_API_JS)) {
            fileName = StrUtil.format("{}/api/{}/{}.js" , vuePath, moduleName, businessName);
        } else if (template.contains(VM_INDEX_VUE)) {
            fileName = StrUtil.format("{}/views/{}/{}/index.vue" , vuePath, moduleName, businessName);
        }
        return fileName;
    }
}
