package com.codechecker.config;

import org.yaml.snakeyaml.Yaml;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 读取 .gitea/workflows/code-check-config.yaml，提供检测开关、扫描目录、企微配置等。
 */
public class AppConfig {
    private boolean masterEnabled = true;
    private boolean classCheckEnabled = true;
    private boolean dtoEntityConversionEnabled = true;
    private List<String> modelDirs = new ArrayList<>();
    private List<String> controllerScanDirs = new ArrayList<>();
    private List<String> feignScanDirs = new ArrayList<>();
    private List<String> conversionScanDirs = new ArrayList<>();
    private String wecomWebhookUrl = "";
    private boolean wecomEnabled = true;
    private boolean onlyOnChange = true;

    private boolean dtoApiFollowUpEnabled = true;
    private int nestMaxDepth = 3;
    private boolean apiCheckEnabled = true;
    private boolean apiExcludeFrameworkParams = true;
    private List<String> apiControllerScanDirs = new ArrayList<>();
    private List<String> apiFeignScanDirs = new ArrayList<>();
    private DtoOverlapMode dtoOverlapMode = DtoOverlapMode.BOTH;

    /** 从 YAML 文件加载配置 */
    @SuppressWarnings("unchecked")
    public static AppConfig load(Path configPath) throws IOException {
        Yaml yaml = new Yaml();
        Map<String, Object> root;
        try (InputStream in = Files.newInputStream(configPath)) {
            root = yaml.load(in);
        }
        if (root == null) {
            root = Map.of();
        }

        AppConfig config = new AppConfig();
        Map<String, Object> checker = mapOrEmpty(root.get("checker"));
        config.masterEnabled = boolOrDefault(checker.get("enabled"), true);

        Map<String, Object> classCheck = mapOrEmpty(root.get("class_check"));
        config.classCheckEnabled = boolOrDefault(classCheck.get("enabled"), true);

        Map<String, Object> dtoApiFollowUp = mapOrEmpty(classCheck.get("dto_api_follow_up"));
        config.dtoApiFollowUpEnabled = boolOrDefault(dtoApiFollowUp.get("enabled"), true);

        Map<String, Object> nestIndex = mapOrEmpty(classCheck.get("nest_index"));
        config.nestMaxDepth = intOrDefault(nestIndex.get("max_depth"), 3);

        Map<String, Object> conversion = mapOrEmpty(classCheck.get("dto_entity_conversion"));
        config.dtoEntityConversionEnabled = boolOrDefault(conversion.get("enabled"), true);

        config.modelDirs = stringList(classCheck.get("model_dirs"));
        Map<String, Object> endpointScan = mapOrEmpty(classCheck.get("endpoint_scan"));
        config.controllerScanDirs = stringList(endpointScan.get("controllers"));
        config.feignScanDirs = stringList(endpointScan.get("feign_apis"));
        config.conversionScanDirs = stringList(classCheck.get("conversion_scan"));

        Map<String, Object> wecom = mapOrEmpty(root.get("wecom"));
        config.wecomWebhookUrl = stringOrEmpty(wecom.get("webhook_url"));
        config.wecomEnabled = boolOrDefault(wecom.get("enabled"), true);

        Map<String, Object> notify = mapOrEmpty(root.get("notify"));
        config.onlyOnChange = boolOrDefault(notify.get("only_on_change"), true);
        config.dtoOverlapMode = DtoOverlapMode.fromString(stringOrEmpty(notify.get("dto_overlap_mode")));

        Map<String, Object> apiCheck = mapOrEmpty(root.get("api_check"));
        config.apiCheckEnabled = boolOrDefault(apiCheck.get("enabled"), true);
        config.apiExcludeFrameworkParams = boolOrDefault(apiCheck.get("exclude_framework_params"), true);
        Map<String, Object> apiEndpointScan = mapOrEmpty(apiCheck.get("endpoint_scan"));
        config.apiControllerScanDirs = stringList(apiEndpointScan.get("controllers"));
        config.apiFeignScanDirs = stringList(apiEndpointScan.get("feign_apis"));
        if (config.apiControllerScanDirs.isEmpty()) {
            config.apiControllerScanDirs = new ArrayList<>(config.controllerScanDirs);
        }
        if (config.apiFeignScanDirs.isEmpty()) {
            config.apiFeignScanDirs = new ArrayList<>(config.feignScanDirs);
        }

        return config;
    }

    /** 安全转为 Map，非 Map 则返回空 Map */
    @SuppressWarnings("unchecked")
    private static Map<String, Object> mapOrEmpty(Object value) {
        if (value instanceof Map) {
            return (Map<String, Object>) value;
        }
        return Map.of();
    }

    /** 安全转为字符串列表 */
    @SuppressWarnings("unchecked")
    private static List<String> stringList(Object value) {
        if (value instanceof List) {
            List<?> list = (List<?>) value;
            List<String> result = new ArrayList<>();
            for (Object item : list) {
                if (item != null) {
                    result.add(item.toString());
                }
            }
            return result;
        }
        return new ArrayList<>();
    }

    /** 安全转为 boolean，缺省用 defaultValue */
    private static boolean boolOrDefault(Object value, boolean defaultValue) {
        if (value instanceof Boolean) {
            return (Boolean) value;
        }
        return defaultValue;
    }

    /** 安全转为 int，缺省用 defaultValue */
    private static int intOrDefault(Object value, int defaultValue) {
        if (value instanceof Number) {
            return ((Number) value).intValue();
        }
        if (value != null) {
            try {
                return Integer.parseInt(value.toString().trim());
            } catch (NumberFormatException ignored) {
                // 使用默认值
            }
        }
        return defaultValue;
    }

    /** 安全转为字符串，null 则空串 */
    private static String stringOrEmpty(Object value) {
        return value == null ? "" : value.toString();
    }

    /** 变更检测总开关（checker.enabled，控制 class_check + api_check） */
    public boolean isMasterEnabled() {
        return masterEnabled;
    }

    /** 类变更检测开关（class_check.enabled） */
    public boolean isClassCheckEnabled() {
        return classCheckEnabled;
    }

    /** Dto→Entity 类转换检测开关 */
    public boolean isDtoEntityConversionEnabled() {
        return dtoEntityConversionEnabled;
    }

    /** 模型类目录（预留，当前扫描仍按类名后缀） */
    public List<String> getModelDirs() {
        return modelDirs;
    }

    /** Controller 扫描目录 */
    public List<String> getControllerScanDirs() {
        return controllerScanDirs;
    }

    /** Feign 接口扫描目录 */
    public List<String> getFeignScanDirs() {
        return feignScanDirs;
    }

    /** BeanUtils / convert 扫描目录 */
    public List<String> getConversionScanDirs() {
        return conversionScanDirs;
    }

    /** 企微 Webhook 地址 */
    public String getWecomWebhookUrl() {
        return wecomWebhookUrl;
    }

    /** 企微通知开关 */
    public boolean isWecomEnabled() {
        return wecomEnabled;
    }

    /** 无变更时是否打印提示后退出 */
    public boolean isOnlyOnChange() {
        return onlyOnChange;
    }

    /** Dto 类变更后是否继续检测受影响接口的 API 参数变更 */
    public boolean isDtoApiFollowUpEnabled() {
        return dtoApiFollowUpEnabled;
    }

    /** Dto/Vo 嵌套展开最大深度（默认 3，可按需调至 4、5） */
    public int getNestMaxDepth() {
        return nestMaxDepth;
    }

    /** API 变更检测总开关 */
    public boolean isApiCheckEnabled() {
        return apiCheckEnabled;
    }

    /** Dto 类变更与 API 参数变更重叠时的通知策略 */
    public DtoOverlapMode getDtoOverlapMode() {
        return dtoOverlapMode;
    }

    /** 是否排除 Spring 框架注入参数 */
    public boolean isApiExcludeFrameworkParams() {
        return apiExcludeFrameworkParams;
    }

    /** API 检测 Controller 扫描目录 */
    public List<String> getApiControllerScanDirs() {
        return apiControllerScanDirs;
    }

    /** API 检测 Feign 扫描目录 */
    public List<String> getApiFeignScanDirs() {
        return apiFeignScanDirs;
    }

    /** API 检测所有扫描目录（Controller + Feign） */
    public List<String> getAllApiScanDirs() {
        List<String> dirs = new ArrayList<>();
        dirs.addAll(apiControllerScanDirs);
        dirs.addAll(apiFeignScanDirs);
        return dirs;
    }
}
