package com.lesingle.modules.biz.review.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lesingle.common.enums.ErrorCode;
import com.lesingle.common.enums.PublishStatus;
import com.lesingle.common.enums.Visibility;
import com.lesingle.common.enums.WorkStatus;
import com.lesingle.common.exception.BusinessException;
import com.lesingle.common.result.PageResult;
import com.lesingle.modules.biz.contest.entity.BizContest;
import com.lesingle.modules.biz.contest.entity.BizContestRegistration;
import com.lesingle.modules.biz.contest.entity.BizContestWork;
import com.lesingle.modules.biz.contest.mapper.ContestMapper;
import com.lesingle.modules.biz.contest.mapper.ContestRegistrationMapper;
import com.lesingle.modules.biz.contest.mapper.ContestWorkMapper;
import com.lesingle.modules.biz.review.dto.AutoSetAwardsDto;
import com.lesingle.modules.biz.review.dto.BatchSetAwardsDto;
import com.lesingle.modules.biz.review.dto.SetAwardDto;
import com.lesingle.modules.biz.review.entity.BizContestJudge;
import com.lesingle.modules.biz.review.entity.BizContestReviewRule;
import com.lesingle.modules.biz.review.entity.BizContestWorkScore;
import com.lesingle.modules.biz.review.mapper.ContestJudgeMapper;
import com.lesingle.modules.biz.review.mapper.ContestReviewRuleMapper;
import com.lesingle.modules.biz.review.mapper.ContestWorkScoreMapper;
import com.lesingle.modules.biz.review.service.IContestResultService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class ContestResultServiceImpl implements IContestResultService {

    private final ContestWorkMapper workMapper;
    private final ContestMapper contestMapper;
    private final ContestRegistrationMapper contestRegistrationMapper;
    private final ContestReviewRuleMapper reviewRuleMapper;
    private final ContestWorkScoreMapper scoreMapper;
    private final ContestJudgeMapper judgeMapper;

    @Override
    public Map<String, Object> calculateAllFinalScores(Long contestId) {
        log.info("批量计算终分，活动ID：{}", contestId);

        BizContest contest = contestMapper.selectById(contestId);
        if (contest == null) {
            throw BusinessException.of(ErrorCode.NOT_FOUND, "活动不存在");
        }

        // 获取计算规则
        String calculationRule = "average";
        if (contest.getReviewRuleId() != null) {
            BizContestReviewRule rule = reviewRuleMapper.selectById(contest.getReviewRuleId());
            if (rule != null && StringUtils.hasText(rule.getCalculationRule())) {
                calculationRule = rule.getCalculationRule();
            }
        }

        // 获取评委权重
        LambdaQueryWrapper<BizContestJudge> judgeWrapper = new LambdaQueryWrapper<>();
        judgeWrapper.eq(BizContestJudge::getContestId, contestId);
        judgeWrapper.eq(BizContestJudge::getValidState, 1);
        List<BizContestJudge> judges = judgeMapper.selectList(judgeWrapper);
        Map<Long, BigDecimal> weightMap = new HashMap<>();
        for (BizContestJudge j : judges) {
            weightMap.put(j.getJudgeId(), j.getWeight() != null ? j.getWeight() : BigDecimal.ONE);
        }

        // 获取所有最新有效作品
        LambdaQueryWrapper<BizContestWork> workWrapper = new LambdaQueryWrapper<>();
        workWrapper.eq(BizContestWork::getContestId, contestId);
        workWrapper.eq(BizContestWork::getIsLatest, true);
        workWrapper.eq(BizContestWork::getValidState, 1);
        List<BizContestWork> works = workMapper.selectList(workWrapper);

        // 获取所有评分记录
        LambdaQueryWrapper<BizContestWorkScore> scoreWrapper = new LambdaQueryWrapper<>();
        scoreWrapper.eq(BizContestWorkScore::getContestId, contestId);
        scoreWrapper.eq(BizContestWorkScore::getValidState, 1);
        List<BizContestWorkScore> allScores = scoreMapper.selectList(scoreWrapper);

        // 按作品分组
        Map<Long, List<BizContestWorkScore>> scoresByWork = allScores.stream()
                .collect(Collectors.groupingBy(BizContestWorkScore::getWorkId));

        int calculatedCount = 0;

        for (BizContestWork work : works) {
            List<BizContestWorkScore> workScores = scoresByWork.get(work.getId());
            if (workScores == null || workScores.isEmpty()) {
                continue;
            }

            BigDecimal finalScore = doCalculate(workScores, calculationRule, weightMap);
            if (finalScore != null) {
                work.setFinalScore(finalScore);
                workMapper.updateById(work);
                calculatedCount++;
            }
        }

        log.info("批量计算终分完成，活动ID：{}，计算数量：{}", contestId, calculatedCount);

        Map<String, Object> result = new LinkedHashMap<>();
        result.put("calculatedCount", calculatedCount);
        result.put("calculationRule", calculationRule);
        return result;
    }

    @Override
    public Map<String, Object> calculateRankings(Long contestId) {
        log.info("计算排名，活动ID：{}", contestId);

        LambdaQueryWrapper<BizContestWork> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BizContestWork::getContestId, contestId);
        wrapper.eq(BizContestWork::getIsLatest, true);
        wrapper.eq(BizContestWork::getValidState, 1);
        wrapper.isNotNull(BizContestWork::getFinalScore);
        wrapper.orderByDesc(BizContestWork::getFinalScore);

        List<BizContestWork> works = workMapper.selectList(wrapper);

        // 密集排名：相同分数 = 相同名次
        int currentRank = 1;
        BigDecimal previousScore = null;
        for (int i = 0; i < works.size(); i++) {
            BigDecimal score = works.get(i).getFinalScore();
            if (previousScore == null || score.compareTo(previousScore) != 0) {
                currentRank = i + 1;
            }
            works.get(i).setRank(currentRank);
            previousScore = score;
        }

        // 批量更新排名
        for (BizContestWork work : works) {
            workMapper.updateById(work);
        }

        log.info("排名计算完成，活动ID：{}，排名数量：{}", contestId, works.size());

        Map<String, Object> result = new LinkedHashMap<>();
        result.put("rankedCount", works.size());
        return result;
    }

    @Override
    public void setAward(Long workId, SetAwardDto dto) {
        log.info("设置奖项，作品ID：{}", workId);

        BizContestWork work = workMapper.selectById(workId);
        if (work == null) {
            throw BusinessException.of(ErrorCode.NOT_FOUND, "作品不存在");
        }

        work.setAwardLevel(dto.getAwardLevel());
        work.setAwardName(dto.getAwardName());
        work.setCertificateUrl(dto.getCertificateUrl());
        workMapper.updateById(work);

        log.info("奖项设置成功，作品ID：{}，等级：{}", workId, dto.getAwardLevel());
    }

    @Override
    public Map<String, Object> batchSetAwards(Long contestId, BatchSetAwardsDto dto) {
        log.info("批量设置奖项，活动ID：{}，数量：{}", contestId, dto.getAwards().size());

        int updated = 0;
        for (BatchSetAwardsDto.AwardItem item : dto.getAwards()) {
            BizContestWork work = workMapper.selectById(item.getWorkId());
            if (work != null && work.getContestId().equals(contestId)) {
                work.setAwardLevel(item.getAwardLevel());
                work.setAwardName(item.getAwardName());
                workMapper.updateById(work);
                updated++;
            }
        }

        log.info("批量设置奖项完成，更新数量：{}", updated);

        Map<String, Object> result = new LinkedHashMap<>();
        result.put("updatedCount", updated);
        return result;
    }

    @Override
    public Map<String, Object> autoSetAwards(Long contestId, AutoSetAwardsDto dto) {
        log.info("自动设置奖项，活动ID：{}", contestId);

        // 1. 获取已排名作品，按排名排序
        LambdaQueryWrapper<BizContestWork> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BizContestWork::getContestId, contestId);
        wrapper.eq(BizContestWork::getIsLatest, true);
        wrapper.eq(BizContestWork::getValidState, 1);
        wrapper.isNotNull(BizContestWork::getRank);
        wrapper.orderByAsc(BizContestWork::getRank);

        List<BizContestWork> rankedWorks = workMapper.selectList(wrapper);

        if (rankedWorks.isEmpty()) {
            throw BusinessException.of(ErrorCode.BAD_REQUEST, "没有已排名的作品，请先计算排名");
        }

        // 2. 展开奖项配置
        List<String> awardSlots = new ArrayList<>();
        List<AutoSetAwardsDto.AwardTier> tiers = dto.getAwards();
        for (int tierIndex = 0; tierIndex < tiers.size(); tierIndex++) {
            AutoSetAwardsDto.AwardTier tier = tiers.get(tierIndex);
            for (int j = 0; j < tier.getCount(); j++) {
                awardSlots.add(tier.getName());
            }
        }

        // 3. 按序分配
        int assignedCount = 0;
        int tierIndex = 0;
        int slotIndex = 0;
        for (int i = 0; i < Math.min(rankedWorks.size(), awardSlots.size()); i++) {
            BizContestWork work = rankedWorks.get(i);

            // 确定当前tierIndex
            int accumulated = 0;
            for (int t = 0; t < tiers.size(); t++) {
                accumulated += tiers.get(t).getCount();
                if (i < accumulated) {
                    tierIndex = t;
                    break;
                }
            }

            work.setAwardName(awardSlots.get(i));
            work.setAwardLevel("tier_" + tierIndex);
            workMapper.updateById(work);
            assignedCount++;
        }

        log.info("自动设置奖项完成，分配数量：{}", assignedCount);

        Map<String, Object> result = new LinkedHashMap<>();
        result.put("assignedCount", assignedCount);
        result.put("awards", dto.getAwards());
        return result;
    }

    @Override
    public void publishResults(Long contestId) {
        log.info("发布成果，活动ID：{}", contestId);

        BizContest contest = contestMapper.selectById(contestId);
        if (contest == null) {
            throw BusinessException.of(ErrorCode.NOT_FOUND, "活动不存在");
        }

        // 验证有排名作品
        LambdaQueryWrapper<BizContestWork> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BizContestWork::getContestId, contestId);
        wrapper.eq(BizContestWork::getIsLatest, true);
        wrapper.eq(BizContestWork::getValidState, 1);
        wrapper.isNotNull(BizContestWork::getRank);
        long rankedCount = workMapper.selectCount(wrapper);

        if (rankedCount == 0) {
            throw BusinessException.of(ErrorCode.BAD_REQUEST, "没有已排名的作品，请先计算排名");
        }

        contest.setResultState(PublishStatus.PUBLISHED.getValue());
        contest.setResultPublishTime(LocalDateTime.now());
        contest.setStatus("finished");
        contestMapper.updateById(contest);

        log.info("成果发布成功，活动ID：{}", contestId);
    }

    @Override
    public void unpublishResults(Long contestId) {
        log.info("撤回成果，活动ID：{}", contestId);

        BizContest contest = contestMapper.selectById(contestId);
        if (contest == null) {
            throw BusinessException.of(ErrorCode.NOT_FOUND, "活动不存在");
        }

        if (!PublishStatus.PUBLISHED.getValue().equals(contest.getResultState())) {
            throw BusinessException.of(ErrorCode.BAD_REQUEST, "成果未发布，无法撤回");
        }

        contest.setResultState(PublishStatus.UNPUBLISHED.getValue());
        contest.setResultPublishTime(null);
        contestMapper.updateById(contest);

        log.info("成果撤回成功，活动ID：{}", contestId);
    }

    @Override
    public PageResult<Map<String, Object>> getResults(Long contestId, Long page, Long pageSize, String workNo, String accountNo) {
        log.info("查询成果列表，活动ID：{}，页码：{}", contestId, page);

        LambdaQueryWrapper<BizContestWork> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BizContestWork::getContestId, contestId);
        wrapper.eq(BizContestWork::getIsLatest, true);
        wrapper.eq(BizContestWork::getValidState, 1);
        wrapper.isNotNull(BizContestWork::getFinalScore);

        if (StringUtils.hasText(workNo)) {
            wrapper.like(BizContestWork::getWorkNo, workNo);
        }
        if (StringUtils.hasText(accountNo)) {
            LambdaQueryWrapper<BizContestRegistration> regQw = new LambdaQueryWrapper<>();
            regQw.eq(BizContestRegistration::getContestId, contestId);
            regQw.eq(BizContestRegistration::getValidState, 1);
            regQw.like(BizContestRegistration::getAccountNo, accountNo);
            List<Long> matchRegIds = contestRegistrationMapper.selectList(regQw).stream()
                    .map(BizContestRegistration::getId)
                    .collect(Collectors.toList());
            wrapper.and(q -> {
                q.like(BizContestWork::getSubmitterAccountNo, accountNo);
                if (!matchRegIds.isEmpty()) {
                    q.or().in(BizContestWork::getRegistrationId, matchRegIds);
                }
            });
        }

        wrapper.orderByDesc(BizContestWork::getFinalScore);

        Page<BizContestWork> pageObj = new Page<>(page, pageSize);
        Page<BizContestWork> result = workMapper.selectPage(pageObj, wrapper);

        List<BizContestWork> records = result.getRecords();
        Set<Long> registrationIds = records.stream()
                .map(BizContestWork::getRegistrationId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        Map<Long, BizContestRegistration> registrationById = new HashMap<>();
        if (!registrationIds.isEmpty()) {
            for (BizContestRegistration reg : contestRegistrationMapper.selectBatchIds(registrationIds)) {
                registrationById.put(reg.getId(), reg);
            }
        }

        List<Map<String, Object>> voList = records.stream().map(w -> {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("id", w.getId());
            map.put("workId", w.getId());
            map.put("workNo", w.getWorkNo());
            map.put("title", w.getTitle());
            map.put("submitterAccountNo", w.getSubmitterAccountNo());
            map.put("previewUrl", w.getPreviewUrl());
            map.put("finalScore", w.getFinalScore());
            map.put("rank", w.getRank());
            map.put("awardLevel", w.getAwardLevel());
            map.put("awardName", w.getAwardName());
            map.put("certificateUrl", w.getCertificateUrl());
            map.put("submitTime", w.getSubmitTime());
            BizContestRegistration reg = w.getRegistrationId() != null
                    ? registrationById.get(w.getRegistrationId())
                    : null;
            map.put("registration", reg != null ? registrationToNestedMap(reg) : null);
            return map;
        }).collect(Collectors.toList());

        return PageResult.from(result, voList);
    }

    @Override
    public PageResult<Map<String, Object>> getPublicResults(Long contestId, Long page, Long pageSize) {
        BizContest contest = contestMapper.selectById(contestId);
        if (contest == null) {
            throw BusinessException.of(ErrorCode.NOT_FOUND, "活动不存在");
        }
        if (!Visibility.PUBLIC.getValue().equals(contest.getVisibility())) {
            throw BusinessException.of(ErrorCode.NOT_FOUND, "活动不存在");
        }
        if (!PublishStatus.PUBLISHED.getValue().equals(contest.getResultState())) {
            throw BusinessException.of(ErrorCode.BAD_REQUEST, "成果未发布");
        }

        LambdaQueryWrapper<BizContestWork> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BizContestWork::getContestId, contestId);
        wrapper.eq(BizContestWork::getIsLatest, true);
        wrapper.eq(BizContestWork::getValidState, 1);
        wrapper.isNotNull(BizContestWork::getFinalScore);
        // 评委标记违规或下架的作品不参与公示
        wrapper.notIn(BizContestWork::getStatus,
                List.of(WorkStatus.VIOLATION.getValue(), WorkStatus.TAKEN_DOWN.getValue()));
        wrapper.orderByDesc(BizContestWork::getFinalScore);

        Page<BizContestWork> pageObj = new Page<>(page, pageSize);
        Page<BizContestWork> result = workMapper.selectPage(pageObj, wrapper);

        List<BizContestWork> records = result.getRecords();
        Set<Long> registrationIds = records.stream()
                .map(BizContestWork::getRegistrationId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        Map<Long, BizContestRegistration> registrationById = new HashMap<>();
        if (!registrationIds.isEmpty()) {
            for (BizContestRegistration reg : contestRegistrationMapper.selectBatchIds(registrationIds)) {
                registrationById.put(reg.getId(), reg);
            }
        }

        List<Map<String, Object>> voList = records.stream().map(w -> {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("id", w.getId());
            map.put("workNo", w.getWorkNo());
            map.put("title", w.getTitle());
            map.put("finalScore", w.getFinalScore());
            map.put("rank", w.getRank());
            map.put("awardName", w.getAwardName());
            BizContestRegistration reg = w.getRegistrationId() != null
                    ? registrationById.get(w.getRegistrationId())
                    : null;
            map.put("participantName", buildPublicParticipantName(contest, reg));
            return map;
        }).collect(Collectors.toList());

        return PageResult.from(result, voList);
    }

    /**
     * 公众展示用作者名：团队赛优先队名，否则为报名展示名（非登录账号）。
     */
    private String buildPublicParticipantName(BizContest contest, BizContestRegistration reg) {
        if (reg == null) {
            return "-";
        }
        if ("team".equals(contest.getContestType())) {
            if (StringUtils.hasText(reg.getTeamName())) {
                return reg.getTeamName();
            }
            return StringUtils.hasText(reg.getAccountName()) ? reg.getAccountName() : "-";
        }
        if (StringUtils.hasText(reg.getAccountName())) {
            return reg.getAccountName();
        }
        if (StringUtils.hasText(reg.getTeamName())) {
            return reg.getTeamName();
        }
        return "-";
    }

    @Override
    public Map<String, Object> getResultsSummary(Long contestId) {
        log.info("查询成果概览，活动ID：{}", contestId);

        LambdaQueryWrapper<BizContestWork> baseWrapper = new LambdaQueryWrapper<>();
        baseWrapper.eq(BizContestWork::getContestId, contestId);
        baseWrapper.eq(BizContestWork::getIsLatest, true);
        baseWrapper.eq(BizContestWork::getValidState, 1);
        long totalWorks = workMapper.selectCount(baseWrapper);

        LambdaQueryWrapper<BizContestWork> scoredWrapper = new LambdaQueryWrapper<>();
        scoredWrapper.eq(BizContestWork::getContestId, contestId);
        scoredWrapper.eq(BizContestWork::getIsLatest, true);
        scoredWrapper.eq(BizContestWork::getValidState, 1);
        scoredWrapper.isNotNull(BizContestWork::getFinalScore);
        long scoredWorks = workMapper.selectCount(scoredWrapper);

        LambdaQueryWrapper<BizContestWork> rankedWrapper = new LambdaQueryWrapper<>();
        rankedWrapper.eq(BizContestWork::getContestId, contestId);
        rankedWrapper.eq(BizContestWork::getIsLatest, true);
        rankedWrapper.eq(BizContestWork::getValidState, 1);
        rankedWrapper.isNotNull(BizContestWork::getRank);
        long rankedWorks = workMapper.selectCount(rankedWrapper);

        LambdaQueryWrapper<BizContestWork> awardedWrapper = new LambdaQueryWrapper<>();
        awardedWrapper.eq(BizContestWork::getContestId, contestId);
        awardedWrapper.eq(BizContestWork::getIsLatest, true);
        awardedWrapper.eq(BizContestWork::getValidState, 1);
        awardedWrapper.isNotNull(BizContestWork::getAwardLevel);
        long awardedWorks = workMapper.selectCount(awardedWrapper);

        // 分数统计
        LambdaQueryWrapper<BizContestWork> scoreStatsWrapper = new LambdaQueryWrapper<>();
        scoreStatsWrapper.eq(BizContestWork::getContestId, contestId);
        scoreStatsWrapper.eq(BizContestWork::getIsLatest, true);
        scoreStatsWrapper.eq(BizContestWork::getValidState, 1);
        scoreStatsWrapper.isNotNull(BizContestWork::getFinalScore);
        scoreStatsWrapper.orderByDesc(BizContestWork::getFinalScore);
        List<BizContestWork> scoredList = workMapper.selectList(scoreStatsWrapper);

        BigDecimal avgScore = BigDecimal.ZERO;
        BigDecimal maxScore = BigDecimal.ZERO;
        BigDecimal minScore = BigDecimal.ZERO;

        if (!scoredList.isEmpty()) {
            BigDecimal sum = scoredList.stream()
                    .map(BizContestWork::getFinalScore)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            avgScore = sum.divide(BigDecimal.valueOf(scoredList.size()), 2, RoundingMode.HALF_UP);
            maxScore = scoredList.get(0).getFinalScore();
            minScore = scoredList.get(scoredList.size() - 1).getFinalScore();
        }

        // 奖项分布
        Map<String, Long> awardDistribution = new LinkedHashMap<>();
        for (BizContestWork w : scoredList) {
            if (w.getAwardName() != null) {
                awardDistribution.merge(w.getAwardName(), 1L, Long::sum);
            }
        }

        BizContest contest = contestMapper.selectById(contestId);
        if (contest == null) {
            throw BusinessException.of(ErrorCode.NOT_FOUND, "活动不存在");
        }

        Map<String, Object> contestMap = new LinkedHashMap<>();
        contestMap.put("id", contest.getId());
        contestMap.put("contestName", contest.getContestName());
        contestMap.put("resultState", contest.getResultState());
        contestMap.put("resultPublishTime", contest.getResultPublishTime());
        contestMap.put("contestType", contest.getContestType());

        long unscoredWorks = Math.max(0, totalWorks - scoredWorks);

        Map<String, Object> summaryMap = new LinkedHashMap<>();
        summaryMap.put("totalWorks", totalWorks);
        summaryMap.put("scoredWorks", scoredWorks);
        summaryMap.put("rankedWorks", rankedWorks);
        summaryMap.put("awardedWorks", awardedWorks);
        summaryMap.put("unscoredWorks", unscoredWorks);

        Map<String, Object> scoreStats = new LinkedHashMap<>();
        scoreStats.put("avgScore", scoredList.isEmpty() ? null : avgScore.toPlainString());
        scoreStats.put("maxScore", scoredList.isEmpty() ? null : maxScore.toPlainString());
        scoreStats.put("minScore", scoredList.isEmpty() ? null : minScore.toPlainString());

        Map<String, Object> result = new LinkedHashMap<>();
        result.put("contest", contestMap);
        result.put("summary", summaryMap);
        result.put("scoreStats", scoreStats);
        result.put("awardDistribution", awardDistribution);
        return result;
    }

    // ====== 私有辅助方法 ======

    /**
     * 与前端成果列表/作品管理一致：registration.user / registration.team 结构
     */
    private Map<String, Object> registrationToNestedMap(BizContestRegistration reg) {
        Map<String, Object> regMap = new LinkedHashMap<>();
        Map<String, Object> user = new LinkedHashMap<>();
        user.put("id", reg.getUserId());
        user.put("username", reg.getAccountNo());
        user.put("nickname", reg.getAccountName());
        regMap.put("user", user);
        Map<String, Object> team = null;
        if ("team".equals(reg.getRegistrationType())
                && (reg.getTeamId() != null || StringUtils.hasText(reg.getTeamName()))) {
            team = new LinkedHashMap<>();
            team.put("id", reg.getTeamId());
            team.put("teamName", reg.getTeamName());
        }
        regMap.put("team", team);
        return regMap;
    }

    private BigDecimal doCalculate(List<BizContestWorkScore> scores, String calculationRule, Map<Long, BigDecimal> weightMap) {
        List<BigDecimal> scoreValues = scores.stream()
                .map(BizContestWorkScore::getTotalScore)
                .sorted()
                .collect(Collectors.toList());

        switch (calculationRule) {
            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 = weightMap.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) {
                    // 不足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);
        }
    }
}
