package com.agri.generator.util;


import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.agri.generator.dto.ApiConfigDTO;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 代码生成工具类
 */
@Component
public class CodeGenerator {
    private final ConversionService conversionService;
    // Freemarker配置
    private Configuration freemarkerConfig;

    // 代码生成根目录（可配置到application.yml）
    private static final String CODE_ROOT_PATH = System.getProperty("user.dir") + "/generated-code/";
    // 基础包名
    private static final String BASE_PACKAGE = "com.example.api";
    // 日期格式化器
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    public CodeGenerator(@Qualifier("mvcConversionService")ConversionService conversionService) {
        this.conversionService = conversionService;
    }

    @PostConstruct
    public void init() {
        // 初始化Freemarker
        freemarkerConfig = new Configuration(Configuration.VERSION_2_3_31);

        // 设置模板目录（resources/templates）
        freemarkerConfig.setClassForTemplateLoading(this.getClass(), "/templates/");
        freemarkerConfig.setDefaultEncoding("UTF-8");

        // 创建代码根目录
        FileUtil.mkdir(CODE_ROOT_PATH);
    }

    /**
     * 生成接口相关代码（实体+接口方法+枚举）
     */
    public void generateApiCode(ApiConfigDTO apiConfig) {
        if (apiConfig == null) {
            throw new IllegalArgumentException("接口配置参数不能为空");
        }
        try {
            // 1. 生成入参实体（仅生成标记为genEntity=true的参数）
            generateRequestEntity(apiConfig);
            // 2. 生成出参实体（仅生成标记为genEntity=true的参数）
            generateResponseEntity(apiConfig);
            // 3. 生成接口方法
            generateApiMethod(apiConfig);
            // 4. 生成枚举（需传入所有接口配置，此处示例传单个，实际可传列表）
            List<ApiConfigDTO> apiList = Collections.singletonList(apiConfig);
            generateApiEnum(apiList);
        } catch (IOException | TemplateException e) {
            throw new RuntimeException("代码生成失败", e);
        }
    }

    /**
     * 生成入参实体
     */
    private void generateRequestEntity(ApiConfigDTO apiConfig) throws IOException, TemplateException {
        // 过滤需要生成实体的入参（JDK 8兼容写法）
        if (!apiConfig.getIsGenRequest()) {
            return;
        }
        List<ApiConfigDTO.ApiParamDTO> requestParams = apiConfig.getRequestParams();
        if (requestParams.isEmpty()) {
            return;
        }

        // 实体类名（路径转驼峰，如/api/user/login → UserLoginRequest）
        String className = getClassName(apiConfig.getRequestPath(), "Request");
        // 模板参数
        Map<String, Object> dataModel = new HashMap<>();
        dataModel.put("packageName", BASE_PACKAGE + ".request");
        dataModel.put("className", className);
        dataModel.put("apiDesc", apiConfig.getApiDesc() == null ? "" : apiConfig.getApiDesc());
        dataModel.put("apiRemark", apiConfig.getApiRemark() == null ? "" : apiConfig.getApiRemark());
        dataModel.put("params", requestParams);
        dataModel.put("createTime", LocalDateTime.now().format(DATE_FORMATTER));

        // 生成文件
        Template template = freemarkerConfig.getTemplate("entity.ftl");
        String filePath = CODE_ROOT_PATH + "request/" + className + ".java";
        writeFile(template, dataModel, filePath);
    }

    /**
     * 生成出参实体
     */
    private void generateResponseEntity(ApiConfigDTO apiConfig) throws IOException, TemplateException {
        if (!apiConfig.getIsGenResponse()) {
            return;
        }
        // 过滤需要生成实体的出参
        List<ApiConfigDTO.ApiParamDTO> responseParams = apiConfig.getResponseParams();
        if (responseParams.isEmpty()) {
            return;
        }

        // 实体类名（路径转驼峰，如/api/user/login → UserLoginResponse）
        String className = getClassName(apiConfig.getRequestPath(), "Response");
        // 模板参数
        Map<String, Object> dataModel = new HashMap<>();
        dataModel.put("packageName", BASE_PACKAGE + ".response");
        dataModel.put("className", className);
        dataModel.put("apiDesc", apiConfig.getApiDesc() == null ? "" : apiConfig.getApiDesc());
        dataModel.put("apiRemark", apiConfig.getApiRemark() == null ? "" : apiConfig.getApiRemark());
        dataModel.put("params", responseParams);
        dataModel.put("createTime", LocalDateTime.now().format(DATE_FORMATTER));

        // 生成文件
        Template template = freemarkerConfig.getTemplate("entity.ftl");
        String filePath = CODE_ROOT_PATH + "response/" + className + ".java";
        writeFile(template, dataModel, filePath);
    }

    /**
     * 生成接口方法
     */
    private void generateApiMethod(ApiConfigDTO apiConfig) throws IOException, TemplateException {
        // 接口类名（路径转驼峰，如/api/user/login → UserLoginApi）
        String className = getClassName(apiConfig.getRequestPath(), "Api");
        // 方法名（路径转小驼峰，如/api/user/login → userLogin）
        String methodName = this.uncapitalize(getClassName(apiConfig.getRequestPath(), ""));
        // 出参实体名（默认用Response，若生成则用实际实体名）
        String responseEntityName = "Response";
        List<ApiConfigDTO.ApiParamDTO> responseParams = apiConfig.getResponseParams();
        if (!responseParams.isEmpty()) {
            responseEntityName = getClassName(apiConfig.getRequestPath(), "Response");
        }

        // 模板参数
        Map<String, Object> dataModel = new HashMap<>();
        dataModel.put("packageName", BASE_PACKAGE + ".controller");
        dataModel.put("className", className);
        dataModel.put("methodName", methodName);
        dataModel.put("requestMethod", "Post"); // 默认POST，可根据实际需求调整
        dataModel.put("requestPath", apiConfig.getRequestPath() == null ? "" : apiConfig.getRequestPath());
        dataModel.put("apiVendor", apiConfig.getApiVendor() == null ? "" : apiConfig.getApiVendor());
        dataModel.put("apiDesc", apiConfig.getApiDesc() == null ? "" : apiConfig.getApiDesc());
        dataModel.put("apiRemark", apiConfig.getApiRemark() == null ? "" : apiConfig.getApiRemark());
        dataModel.put("requestParams", apiConfig.getRequestParams());
        dataModel.put("responseEntityName", responseEntityName);
        dataModel.put("createTime", LocalDateTime.now().format(DATE_FORMATTER));

        // 生成文件
        Template template = freemarkerConfig.getTemplate("apiMethod.ftl");
        String filePath = CODE_ROOT_PATH + "controller/" + className + ".java";
        writeFile(template, dataModel, filePath);
    }

    /**
     * 生成接口路径枚举
     */
    private void generateApiEnum(List<ApiConfigDTO> apiList) throws IOException, TemplateException {
        // 处理枚举数据（路径转枚举名，如/api/user/login → USER_LOGIN）
        List<Map<String, String>> enumDataList = new ArrayList<>();
        for (ApiConfigDTO api : apiList) {
            if (api == null) {
                continue;
            }
            Map<String, String> enumData = new HashMap<>();
            enumData.put("enumName", getEnumName(api.getRequestPath()));
            enumData.put("requestPath", api.getRequestPath() == null ? "" : api.getRequestPath());
            enumData.put("apiDesc", api.getApiDesc() == null ? "" : api.getApiDesc());
            enumDataList.add(enumData);
        }

        // 模板参数
        Map<String, Object> dataModel = new HashMap<>();
        dataModel.put("packageName", BASE_PACKAGE + ".enums");
        dataModel.put("apiList", enumDataList);
        dataModel.put("createTime", LocalDateTime.now().format(DATE_FORMATTER));

        // 生成文件
        Template template = freemarkerConfig.getTemplate("enum.ftl");
        String filePath = CODE_ROOT_PATH + "enums/ApiPathEnum.java";
        writeFile(template, dataModel, filePath);
    }

    /**
     * 路径转类名（如/api/user/login → UserLogin + suffix）
     */
    private String getClassName(String path, String suffix) {
        if (isBlank(path)) {
            return "Default" + suffix;
        }
        // 去除前缀/，按/分割，转驼峰（纯JDK实现）
        String[] parts = path.split("\\.");
        StringBuilder className = new StringBuilder();
        for (String part : parts) {
            if (!Objects.equals(part, "api") && !Objects.equals(part, "v2")) {
                className.append(StrUtil.upperFirst(part));
            }
        }
        // 兜底处理空类名
        if (className.length() == 0) {
            className.append("Default");
        }
        return className + suffix;
    }

    /**
     * 路径转枚举名（如/api/user/login → USER_LOGIN）
     */
    private String getEnumName(String path) {
        if (isBlank(path)) {
            return "DEFAULT_PATH";
        }
        String[] parts = path.split("\\.");
        StringBuilder enumName = new StringBuilder();
        for (int i = 0; i < parts.length; i++) {
            enumName.append(parts[i].toUpperCase());
            if (i < parts.length - 1) {
                enumName.append("_");
            }
        }
        // 兜底处理空枚举名
        if (enumName.length() == 0) {
            enumName.append("DEFAULT_PATH");
        }
        return enumName.toString();
    }

    /**
     * 写入文件（修复IO异常编译错误：明确分离IO异常和Template异常）
     */
    private void writeFile(Template template, Map<String, Object> dataModel, String filePath) throws IOException, TemplateException {
        File file = new File(filePath);
        FileUtil.mkParentDirs(file); // 创建父目录
        try (Writer writer = new FileWriter(file, false)) {
            // 渲染模板并写入文件
            template.process(dataModel, writer);
        }
    }

    // ==================== 替代StrUtil的原生方法 ====================
    /**
     * 判断字符串是否为空（空白字符也算空）
     */
    private boolean isBlank(String str) {
        if (str == null) {
            return true;
        }
        int length = str.length();
        for (int i = 0; i < length; i++) {
            if (!Character.isWhitespace(str.charAt(i))) {
                return false;
            }
        }
        return true;
    }

    /**
     * 判断字符串是否非空
     */
    private boolean isNotBlank(String str) {
        return !isBlank(str);
    }

    /**
     * 去除字符串前缀
     */
    private String removePrefix(String str, String prefix) {
        if (str == null || prefix == null) {
            return str;
        }
        if (str.startsWith(prefix)) {
            return str.substring(prefix.length());
        }
        return str;
    }

    /**
     * 首字母大写
     */
    private String upperFirst(String str) {
        if (isBlank(str)) {
            return str;
        }
        char firstChar = str.charAt(0);
        if (Character.isUpperCase(firstChar)) {
            return str;
        }
        return Character.toUpperCase(firstChar) + str.substring(1);
    }


    /**
     * 首字母小写
     */
    private String uncapitalize(String str) {
        if (isBlank(str)) {
            return str;
        }
        char firstChar = str.charAt(0);
        if (Character.isLowerCase(firstChar)) {
            return str;
        }
        return Character.toLowerCase(firstChar) + str.substring(1);
    }

}