package com.competition.modules.biz.review.util;

import com.competition.modules.biz.review.entity.BizContestWorkScore;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 与 {@code ContestReviewServiceImpl#calculateFinalScore}、成果发布计算逻辑一致的终分计算（列表场景对不足条数规则做温和回退）。
 */
public final class ContestFinalScoreCalculator {

    private ContestFinalScoreCalculator() {
    }

    public static BigDecimal compute(
            List<BizContestWorkScore> scores,
            String calculationRule,
            Map<Long, BigDecimal> weightMap) {
        if (scores == null || scores.isEmpty()) {
            return null;
        }
        String rule = calculationRule != null ? calculationRule : "average";
        Map<Long, BigDecimal> wm = weightMap != null ? weightMap : Collections.emptyMap();

        List<BigDecimal> scoreValues = scores.stream()
                .map(BizContestWorkScore::getTotalScore)
                .sorted()
                .collect(Collectors.toList());

        switch (rule) {
            case "max":
                return Collections.max(scoreValues);
            case "min":
                return Collections.min(scoreValues);
            case "weighted":
                BigDecimal weightedSum = BigDecimal.ZERO;
                BigDecimal totalWeight = BigDecimal.ZERO;
                for (BizContestWorkScore s : scores) {
                    BigDecimal w = wm.getOrDefault(s.getJudgeId(), BigDecimal.ONE);
                    weightedSum = weightedSum.add(s.getTotalScore().multiply(w));
                    totalWeight = totalWeight.add(w);
                }
                return totalWeight.compareTo(BigDecimal.ZERO) > 0
                        ? weightedSum.divide(totalWeight, 2, RoundingMode.HALF_UP)
                        : BigDecimal.ZERO;
            case "remove_max_min":
                if (scoreValues.size() < 3) {
                    BigDecimal sum = scoreValues.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
                    return sum.divide(BigDecimal.valueOf(scoreValues.size()), 2, RoundingMode.HALF_UP);
                }
                List<BigDecimal> trimmed = scoreValues.subList(1, scoreValues.size() - 1);
                BigDecimal trimmedSum = trimmed.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
                return trimmedSum.divide(BigDecimal.valueOf(trimmed.size()), 2, RoundingMode.HALF_UP);
            case "remove_min":
                if (scoreValues.size() < 2) {
                    return scoreValues.get(0);
                }
                List<BigDecimal> withoutMin = scoreValues.subList(1, scoreValues.size());
                BigDecimal withoutMinSum = withoutMin.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
                return withoutMinSum.divide(BigDecimal.valueOf(withoutMin.size()), 2, RoundingMode.HALF_UP);
            case "average":
            default:
                BigDecimal sum = scoreValues.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
                return sum.divide(BigDecimal.valueOf(scoreValues.size()), 2, RoundingMode.HALF_UP);
        }
    }
}
