package com.easyagents.rag.ingestion.recommend;

import com.easyagents.rag.core.RagStrategyCodes;
import com.easyagents.rag.core.RagStructureTypes;
import com.easyagents.rag.ingestion.model.AnalysisResult;
import com.easyagents.rag.ingestion.model.CandidateStrategy;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

public class SplitStrategyRecommender {

    public AnalysisResult recommend(AnalysisResult analysisResult) {
        Map<String, Object> features = analysisResult.getFeatures();
        String sourceFormat = safeLowercase(analysisResult.getSourceFormat());

        double markdownScore = number(features.get("markdownHeadingCount")) * 12
            + number(features.get("markdownLevelVariety")) * 8
            + ("md".equals(sourceFormat) ? 20 : 0);
        double outlineScore = number(features.get("outlineHeadingCount")) * 10
            + (("pdf".equals(sourceFormat) || "docx".equals(sourceFormat)) ? 5 : 0)
            - number(features.get("tocLineCount")) * 4;
        double qaScore = number(features.get("qaQuestionCount")) * 10
            + number(features.get("qaAnswerCount")) * 10
            + number(features.get("pairedQaCount")) * 18;
        double plainScore = 18
            + number(features.get("paragraphCount")) * 2
            + number(features.get("longParagraphCount")) * 3;

        Map<String, Double> scoreMap = new LinkedHashMap<String, Double>();
        scoreMap.put(RagStrategyCodes.MARKDOWN_SECTION, Double.valueOf(markdownScore));
        scoreMap.put(RagStrategyCodes.OUTLINE_SECTION, Double.valueOf(outlineScore));
        scoreMap.put(RagStrategyCodes.QA_PAIR, Double.valueOf(qaScore));
        scoreMap.put(RagStrategyCodes.PARAGRAPH_LENGTH, Double.valueOf(plainScore));

        List<Map.Entry<String, Double>> ranking = new ArrayList<Map.Entry<String, Double>>(scoreMap.entrySet());
        ranking.sort((left, right) -> Double.compare(right.getValue().doubleValue(), left.getValue().doubleValue()));

        Map.Entry<String, Double> best = ranking.get(0);
        Map.Entry<String, Double> second = ranking.size() > 1 ? ranking.get(1) : best;
        double confidence = computeConfidence(best.getValue().doubleValue(), second.getValue().doubleValue());

        String recommendedStrategy = confidence < 0.45D ? RagStrategyCodes.PARAGRAPH_LENGTH : best.getKey();
        analysisResult.setRecommendedStrategyCode(recommendedStrategy);
        analysisResult.setRecommendedStrategyLabel(toStrategyLabel(recommendedStrategy));
        analysisResult.setRecommendedStructureType(toStructureType(recommendedStrategy));
        analysisResult.setConfidence(Double.valueOf(scale(confidence)));
        analysisResult.setReasons(buildReasons(features, recommendedStrategy, confidence));

        List<CandidateStrategy> candidates = new ArrayList<CandidateStrategy>();
        for (Map.Entry<String, Double> entry : ranking) {
            candidates.add(new CandidateStrategy(entry.getKey(), toStrategyLabel(entry.getKey()), Double.valueOf(scale(entry.getValue().doubleValue()))));
        }
        analysisResult.setCandidateStrategies(candidates);
        return analysisResult;
    }

    public String toStructureType(String strategyCode) {
        if (RagStrategyCodes.MARKDOWN_SECTION.equals(strategyCode)) {
            return RagStructureTypes.MARKDOWN_HEADING;
        }
        if (RagStrategyCodes.OUTLINE_SECTION.equals(strategyCode)) {
            return RagStructureTypes.OUTLINE_SECTION;
        }
        if (RagStrategyCodes.QA_PAIR.equals(strategyCode)) {
            return RagStructureTypes.QA_PAIR;
        }
        return RagStructureTypes.PLAIN_PARAGRAPH;
    }

    public String toStrategyLabel(String strategyCode) {
        if (RagStrategyCodes.MARKDOWN_SECTION.equals(strategyCode)) {
            return "Markdown 标题拆分";
        }
        if (RagStrategyCodes.OUTLINE_SECTION.equals(strategyCode)) {
            return "章节标题拆分";
        }
        if (RagStrategyCodes.QA_PAIR.equals(strategyCode)) {
            return "问答对拆分";
        }
        if (RagStrategyCodes.CUSTOM_REGEX.equals(strategyCode)) {
            return "自定义正则拆分";
        }
        if (RagStrategyCodes.AUTO.equals(strategyCode)) {
            return "自动推荐";
        }
        return "自然段长度拆分";
    }

    private List<String> buildReasons(Map<String, Object> features, String strategyCode, double confidence) {
        List<String> reasons = new ArrayList<String>();
        if (RagStrategyCodes.MARKDOWN_SECTION.equals(strategyCode)) {
            reasons.add("检测到 Markdown 标题结构，适合按标题层级拆分");
            reasons.add("标题层级数：" + number(features.get("markdownLevelVariety")) + "，标题数量：" + number(features.get("markdownHeadingCount")));
            return reasons;
        }
        if (RagStrategyCodes.OUTLINE_SECTION.equals(strategyCode)) {
            reasons.add("检测到中英文标题/章节编号，适合按章节拆分");
            reasons.add("章节标题数量：" + number(features.get("outlineHeadingCount")));
            return reasons;
        }
        if (RagStrategyCodes.QA_PAIR.equals(strategyCode)) {
            reasons.add("检测到问答结构，适合按一问一答拆分");
            reasons.add("问题数量：" + number(features.get("qaQuestionCount")) + "，成对问答数量：" + number(features.get("pairedQaCount")));
            return reasons;
        }
        reasons.add("结构特征不够集中，回退为自然段长度拆分");
        reasons.add("推荐置信度：" + scale(confidence));
        return reasons;
    }

    private double computeConfidence(double bestScore, double secondScore) {
        double delta = Math.max(0D, bestScore - secondScore);
        double base = Math.min(1D, bestScore / 100D);
        return Math.min(1D, Math.max(0.25D, base * 0.6D + Math.min(0.4D, delta / 50D)));
    }

    private double number(Object value) {
        if (value instanceof Number) {
            return ((Number) value).doubleValue();
        }
        return 0D;
    }

    private String safeLowercase(String value) {
        return value == null ? "" : value.toLowerCase(Locale.ROOT);
    }

    private double scale(double value) {
        return BigDecimal.valueOf(value).setScale(2, RoundingMode.HALF_UP).doubleValue();
    }
}
