package org.springblade.modules.martial.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.tool.utils.DateUtil;
import org.springblade.modules.martial.excel.ResultExportExcel;
import org.springblade.modules.martial.pojo.entity.MartialAthlete;
import org.springblade.modules.martial.pojo.entity.MartialCompetition;
import org.springblade.modules.martial.pojo.entity.MartialProject;
import org.springblade.modules.martial.pojo.entity.MartialResult;
import org.springblade.modules.martial.mapper.MartialResultMapper;
import org.springblade.modules.martial.pojo.entity.MartialScore;
import org.springblade.modules.martial.pojo.vo.CertificateVO;
import org.springblade.modules.martial.service.IMartialAthleteService;
import org.springblade.modules.martial.service.IMartialCompetitionService;
import org.springblade.modules.martial.service.IMartialProjectService;
import org.springblade.modules.martial.service.IMartialResultService;
import org.springblade.modules.martial.service.IMartialScoreService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Result 服务实现类
 *
 * @author BladeX
 */
@Slf4j
@Service
public class MartialResultServiceImpl extends ServiceImpl<MartialResultMapper, MartialResult> implements IMartialResultService {

	@Autowired
	private IMartialScoreService scoreService;

	@Autowired
	private IMartialAthleteService athleteService;

	@Autowired
	private IMartialProjectService projectService;

	@Autowired
	private IMartialCompetitionService competitionService;

	/**
	 * Task 1.1 & 1.2: 计算有效平均分（去掉最高分和最低分）
	 *
	 * @param athleteId 运动员ID
	 * @param projectId 项目ID
	 * @return 有效平均分
	 */
	public BigDecimal calculateValidAverageScore(Long athleteId, Long projectId) {
		// 1. 获取所有裁判评分
		List<MartialScore> scores = scoreService.list(
			new QueryWrapper<MartialScore>()
				.eq("athlete_id", athleteId)
				.eq("project_id", projectId)
				.eq("is_deleted", 0)
		);

		if (scores.isEmpty()) {
			throw new ServiceException("该运动员尚未有裁判评分");
		}

		if (scores.size() < 3) {
			throw new ServiceException("裁判人数不足3人，无法去最高/最低分");
		}

		// 2. 找出最高分和最低分
		BigDecimal maxScore = scores.stream()
			.map(MartialScore::getScore)
			.max(Comparator.naturalOrder())
			.orElse(BigDecimal.ZERO);

		BigDecimal minScore = scores.stream()
			.map(MartialScore::getScore)
			.min(Comparator.naturalOrder())
			.orElse(BigDecimal.ZERO);

		// 3. 过滤有效评分（去掉一个最高、一个最低）
		List<BigDecimal> validScores = new ArrayList<>();
		boolean maxRemoved = false;
		boolean minRemoved = false;

		for (MartialScore score : scores) {
			BigDecimal val = score.getScore();
			if (!maxRemoved && val.equals(maxScore)) {
				maxRemoved = true;
				continue;
			}
			if (!minRemoved && val.equals(minScore)) {
				minRemoved = true;
				continue;
			}
			validScores.add(val);
		}

		// 4. 计算平均分
		BigDecimal sum = validScores.stream()
			.reduce(BigDecimal.ZERO, BigDecimal::add);

		return sum.divide(
			new BigDecimal(validScores.size()),
			3,
			RoundingMode.HALF_UP
		);
	}

	/**
	 * Task 1.3: 应用难度系数
	 *
	 * @param averageScore 平均分
	 * @param projectId 项目ID
	 * @return 调整后的分数
	 */
	public BigDecimal applyDifficultyCoefficient(BigDecimal averageScore, Long projectId) {
		// 1. 获取项目信息
		MartialProject project = projectService.getById(projectId);
		if (project == null) {
			throw new ServiceException("项目不存在");
		}

		// 2. 获取难度系数（默认1.00）
		BigDecimal coefficient = project.getDifficultyCoefficient();
		if (coefficient == null) {
			coefficient = new BigDecimal("1.00");
		}

		// 3. 应用系数
		return averageScore.multiply(coefficient)
			.setScale(3, RoundingMode.HALF_UP);
	}

	/**
	 * Task 1.4: 计算最终成绩
	 *
	 * @param athleteId 运动员ID
	 * @param projectId 项目ID
	 * @return 成绩记录
	 */
	@Transactional(rollbackFor = Exception.class)
	public MartialResult calculateFinalScore(Long athleteId, Long projectId) {
		// 1. 获取所有裁判评分
		List<MartialScore> scores = scoreService.list(
			new QueryWrapper<MartialScore>()
				.eq("athlete_id", athleteId)
				.eq("project_id", projectId)
				.eq("is_deleted", 0)
		);

		if (scores.isEmpty()) {
			throw new ServiceException("该运动员尚未有裁判评分");
		}

		// 2. 找出最高分和最低分
		BigDecimal maxScore = scores.stream()
			.map(MartialScore::getScore)
			.max(Comparator.naturalOrder())
			.orElse(BigDecimal.ZERO);

		BigDecimal minScore = scores.stream()
			.map(MartialScore::getScore)
			.min(Comparator.naturalOrder())
			.orElse(BigDecimal.ZERO);

		// 3. 去最高/最低分，计算平均分
		BigDecimal averageScore = calculateValidAverageScore(athleteId, projectId);

		// 4. 应用难度系数
		BigDecimal finalScore = applyDifficultyCoefficient(averageScore, projectId);

		// 5. 获取运动员和项目信息
		MartialAthlete athlete = athleteService.getById(athleteId);
		MartialProject project = projectService.getById(projectId);

		// 6. 查询是否已存在成绩记录
		MartialResult existingResult = this.getOne(
			new QueryWrapper<MartialResult>()
				.eq("athlete_id", athleteId)
				.eq("project_id", projectId)
				.eq("is_deleted", 0)
		);

		MartialResult result;
		if (existingResult != null) {
			result = existingResult;
		} else {
			result = new MartialResult();
			result.setCompetitionId(athlete.getCompetitionId());
			result.setAthleteId(athleteId);
			result.setProjectId(projectId);
			result.setPlayerName(athlete.getPlayerName());
			result.setTeamName(athlete.getTeamName());
		}

		// 7. 更新成绩数据
		result.setTotalScore(averageScore);  // 平均分
		result.setMaxScore(maxScore);
		result.setMinScore(minScore);
		result.setValidScoreCount(scores.size() - 2);  // 去掉最高最低

		result.setDifficultyCoefficient(project.getDifficultyCoefficient());
		result.setFinalScore(finalScore);  // 最终得分

		result.setIsFinal(0);  // 初始为非最终成绩

		this.saveOrUpdate(result);

		log.info("计算成绩完成 - 运动员:{}, 项目:{}, 最终得分:{}",
			athlete.getPlayerName(), project.getProjectName(), finalScore);

		return result;
	}

	/**
	 * Task 1.5: 自动排名
	 *
	 * @param projectId 项目ID
	 */
	@Transactional(rollbackFor = Exception.class)
	public void autoRanking(Long projectId) {
		// 1. 获取该项目所有成绩，按分数降序
		List<MartialResult> results = this.list(
			new QueryWrapper<MartialResult>()
				.eq("project_id", projectId)
				.eq("is_deleted", 0)
				.orderByDesc("final_score")
		);

		if (results.isEmpty()) {
			throw new ServiceException("该项目尚无成绩记录");
		}

		// 2. 分配排名（处理并列）
		int currentRank = 1;
		BigDecimal previousScore = null;
		int sameScoreCount = 0;

		for (int i = 0; i < results.size(); i++) {
			MartialResult result = results.get(i);
			BigDecimal currentScore = result.getFinalScore();

			if (currentScore == null) {
				continue;  // 跳过未计算成绩的记录
			}

			if (previousScore != null && currentScore.compareTo(previousScore) == 0) {
				// 分数相同，并列
				sameScoreCount++;
			} else {
				// 分数不同，更新排名
				currentRank += sameScoreCount;
				sameScoreCount = 1;
			}

			result.setRanking(currentRank);
			previousScore = currentScore;
		}

		// 3. 批量更新
		this.updateBatchById(results);

		log.info("自动排名完成 - 项目ID:{}, 共{}条记录", projectId, results.size());
	}

	/**
	 * Task 1.6: 分配奖牌
	 *
	 * @param projectId 项目ID
	 */
	@Transactional(rollbackFor = Exception.class)
	public void assignMedals(Long projectId) {
		// 1. 获取前三名（按排名）
		List<MartialResult> topResults = this.list(
			new QueryWrapper<MartialResult>()
				.eq("project_id", projectId)
				.eq("is_deleted", 0)
				.le("ranking", 3)  // 排名 <= 3
				.orderByAsc("ranking")
		);

		if (topResults.isEmpty()) {
			log.warn("该项目无前三名成绩，无法分配奖牌 - 项目ID:{}", projectId);
			return;
		}

		// 2. 分配奖牌
		for (MartialResult result : topResults) {
			Integer ranking = result.getRanking();
			if (ranking == null) {
				continue;
			}

			if (ranking == 1) {
				result.setMedal(1);  // 金牌
			} else if (ranking == 2) {
				result.setMedal(2);  // 银牌
			} else if (ranking == 3) {
				result.setMedal(3);  // 铜牌
			}
		}

		// 3. 批量更新
		this.updateBatchById(topResults);

		log.info("奖牌分配完成 - 项目ID:{}, 共{}人获奖", projectId, topResults.size());
	}

	/**
	 * Task 1.7: 成绩复核
	 *
	 * @param resultId 成绩ID
	 * @param reviewNote 复核说明
	 * @param adjustment 调整分数（正数为加分，负数为扣分）
	 */
	@Transactional(rollbackFor = Exception.class)
	public void reviewResult(Long resultId, String reviewNote, BigDecimal adjustment) {
		MartialResult result = this.getById(resultId);
		if (result == null) {
			throw new ServiceException("成绩记录不存在");
		}

		// 记录原始分数
		if (result.getOriginalScore() == null) {
			result.setOriginalScore(result.getFinalScore());
		}

		// 应用调整
		if (adjustment != null && adjustment.compareTo(BigDecimal.ZERO) != 0) {
			BigDecimal newScore = result.getFinalScore().add(adjustment);
			result.setAdjustedScore(newScore);
			result.setFinalScore(newScore);
			result.setAdjustRange(adjustment);
		}

		result.setAdjustNote(reviewNote);

		this.updateById(result);

		log.info("成绩复核完成 - 成绩ID:{}, 调整:{}, 说明:{}", resultId, adjustment, reviewNote);

		// 重新排名
		autoRanking(result.getProjectId());
	}

	/**
	 * Task 1.8: 发布成绩
	 *
	 * @param projectId 项目ID
	 */
	@Transactional(rollbackFor = Exception.class)
	public void publishResults(Long projectId) {
		List<MartialResult> results = this.list(
			new QueryWrapper<MartialResult>()
				.eq("project_id", projectId)
				.eq("is_deleted", 0)
		);

		if (results.isEmpty()) {
			throw new ServiceException("该项目无成绩记录");
		}

		for (MartialResult result : results) {
			result.setIsFinal(1);  // 标记为最终成绩
			result.setPublishTime(LocalDateTime.now());
		}

		this.updateBatchById(results);

		log.info("成绩发布完成 - 项目ID:{}, 共{}条成绩", projectId, results.size());
	}

	/**
	 * Task 1.8: 撤销发布
	 *
	 * @param projectId 项目ID
	 */
	@Transactional(rollbackFor = Exception.class)
	public void unpublishResults(Long projectId) {
		List<MartialResult> results = this.list(
			new QueryWrapper<MartialResult>()
				.eq("project_id", projectId)
				.eq("is_final", 1)
				.eq("is_deleted", 0)
		);

		if (results.isEmpty()) {
			log.warn("该项目无已发布的成绩 - 项目ID:{}", projectId);
			return;
		}

		for (MartialResult result : results) {
			result.setIsFinal(0);
			result.setPublishTime(null);
		}

		this.updateBatchById(results);

		log.info("成绩撤销发布完成 - 项目ID:{}, 共{}条成绩", projectId, results.size());
	}

	/**
	 * Task 3.1: 导出成绩单
	 *
	 * @param competitionId 赛事ID
	 * @param projectId 项目ID（可选）
	 * @return 导出数据列表
	 */
	@Override
	public List<ResultExportExcel> exportResults(Long competitionId, Long projectId) {
		// 构建查询条件
		QueryWrapper<MartialResult> wrapper = new QueryWrapper<>();
		wrapper.eq("competition_id", competitionId);
		if (projectId != null) {
			wrapper.eq("project_id", projectId);
		}
		wrapper.eq("is_deleted", 0);
		wrapper.orderByDesc("final_score");

		// 查询成绩数据
		List<MartialResult> results = this.list(wrapper);

		// 转换为导出VO
		return results.stream().map(result -> {
			ResultExportExcel excel = new ResultExportExcel();
			excel.setRanking(result.getRanking());
			excel.setPlayerName(result.getPlayerName());
			excel.setTeamName(result.getTeamName());

			// 查询项目名称
			if (result.getProjectId() != null) {
				MartialProject project = projectService.getById(result.getProjectId());
				if (project != null) {
					excel.setProjectName(project.getProjectName());
					excel.setDifficultyCoefficient(project.getDifficultyCoefficient());
				}
			}

			excel.setOriginalScore(result.getOriginalScore());
			excel.setFinalScore(result.getTotalScore());
			excel.setAdjustNote(result.getAdjustNote());

			// 奖牌名称
			if (result.getMedal() != null) {
				switch (result.getMedal()) {
					case 1: excel.setMedal("金牌"); break;
					case 2: excel.setMedal("银牌"); break;
					case 3: excel.setMedal("铜牌"); break;
					default: excel.setMedal("");
				}
			}

			return excel;
		}).collect(Collectors.toList());
	}

	/**
	 * Task 3.4: 生成证书数据
	 *
	 * @param resultId 成绩ID
	 * @return 证书数据
	 */
	@Override
	public CertificateVO generateCertificateData(Long resultId) {
		// 1. 查询成绩记录
		MartialResult result = this.getById(resultId);
		if (result == null) {
			throw new ServiceException("成绩记录不存在");
		}

		// 2. 检查是否有获奖（前三名）
		if (result.getMedal() == null || result.getMedal() > 3) {
			throw new ServiceException("该选手未获得奖牌，无法生成证书");
		}

		// 3. 查询相关信息
		MartialProject project = projectService.getById(result.getProjectId());
		MartialCompetition competition = competitionService.getById(result.getCompetitionId());

		// 4. 构建证书数据
		CertificateVO certificate = new CertificateVO();
		certificate.setPlayerName(result.getPlayerName());
		certificate.setCompetitionName(competition != null ? competition.getCompetitionName() : "武术比赛");
		certificate.setProjectName(project != null ? project.getProjectName() : "");
		certificate.setRanking(result.getRanking());

		// 5. 奖牌名称和CSS类
		switch (result.getMedal()) {
			case 1:
				certificate.setMedalName("金牌");
				certificate.setMedalClass("gold");
				break;
			case 2:
				certificate.setMedalName("银牌");
				certificate.setMedalClass("silver");
				break;
			case 3:
				certificate.setMedalName("铜牌");
				certificate.setMedalClass("bronze");
				break;
		}

		// 6. 颁发单位和日期
		certificate.setOrganization(competition != null && competition.getOrganizer() != null
			? competition.getOrganizer()
			: "主办单位");
		certificate.setIssueDate(DateUtil.today());

		log.info("生成证书数据 - 选手:{}, 项目:{}, 奖牌:{}",
			result.getPlayerName(), certificate.getProjectName(), certificate.getMedalName());

		return certificate;
	}

	/**
	 * Task 3.4: 批量生成证书数据
	 *
	 * @param projectId 项目ID
	 * @return 证书数据列表
	 */
	@Override
	public List<CertificateVO> batchGenerateCertificates(Long projectId) {
		// 1. 查询获奖选手（前三名）
		List<MartialResult> results = this.list(
			new QueryWrapper<MartialResult>()
				.eq("project_id", projectId)
				.isNotNull("medal")
				.le("medal", 3)
				.eq("is_deleted", 0)
				.orderByAsc("ranking")
		);

		if (results.isEmpty()) {
			throw new ServiceException("该项目暂无获奖选手");
		}

		// 2. 批量生成证书数据
		List<CertificateVO> certificates = new ArrayList<>();
		for (MartialResult result : results) {
			try {
				CertificateVO certificate = generateCertificateData(result.getId());
				certificates.add(certificate);
			} catch (Exception e) {
				log.error("生成证书失败 - 成绩ID:{}, 错误:{}", result.getId(), e.getMessage());
			}
		}

		log.info("批量生成证书完成 - 项目ID:{}, 共{}份证书", projectId, certificates.size());

		return certificates;
	}


	// ========== 三级裁判评分流程方法 ==========

	/**
	 * 主裁判确认/修改分数
	 * 
	 * @param resultId 成绩ID
	 * @param chiefJudgeId 主裁判ID
	 * @param score 确认/修改后的分数（null表示直接确认原分数）
	 * @param note 备注
	 * @return 是否成功
	 */
	@Transactional(rollbackFor = Exception.class)
	public boolean confirmByChiefJudge(Long resultId, Long chiefJudgeId, BigDecimal score, String note) {
		MartialResult result = this.getById(resultId);
		if (result == null) {
			throw new ServiceException("成绩记录不存在");
		}

		// 检查状态：只有裁判员评分完成后才能确认
		if (result.getScoreStatus() != null && result.getScoreStatus() >= MartialResult.SCORE_STATUS_CHIEF_CONFIRMED) {
			throw new ServiceException("该成绩已被主裁判确认，无法重复操作");
		}

		// 确定最终分数
		BigDecimal finalScore = score != null ? score : result.getTotalScore();

		// 验证分数范围（如果有修改）
		if (score != null && result.getTotalScore() != null) {
			BigDecimal minAllowed = result.getTotalScore().subtract(new BigDecimal("0.050"));
			BigDecimal maxAllowed = result.getTotalScore().add(new BigDecimal("0.050"));
			if (score.compareTo(minAllowed) < 0 || score.compareTo(maxAllowed) > 0) {
				throw new ServiceException("修改分数只能在原始总分±0.050范围内");
			}
		}

		// 更新主裁判确认信息
		result.setChiefJudgeScore(finalScore);
		result.setChiefJudgeId(chiefJudgeId);
		result.setChiefJudgeTime(LocalDateTime.now());
		result.setChiefJudgeNote(note);
		result.setScoreStatus(MartialResult.SCORE_STATUS_CHIEF_CONFIRMED);

		// 更新最终得分
		result.setFinalScore(finalScore);

		boolean success = this.updateById(result);

		log.info("主裁判确认成绩 - 成绩ID:{}, 主裁判ID:{}, 原分数:{}, 确认分数:{}, 备注:{}",
			resultId, chiefJudgeId, result.getTotalScore(), finalScore, note);

		return success;
	}

	/**
	 * 总裁确认/修改分数
	 * 
	 * @param resultId 成绩ID
	 * @param generalJudgeId 总裁ID
	 * @param score 确认/修改后的分数（null表示直接确认原分数）
	 * @param note 备注
	 * @return 是否成功
	 */
	@Transactional(rollbackFor = Exception.class)
	public boolean confirmByGeneralJudge(Long resultId, Long generalJudgeId, BigDecimal score, String note) {
		MartialResult result = this.getById(resultId);
		if (result == null) {
			throw new ServiceException("成绩记录不存在");
		}

		// 检查状态：必须主裁判已确认
		if (result.getScoreStatus() == null || result.getScoreStatus() < MartialResult.SCORE_STATUS_CHIEF_CONFIRMED) {
			throw new ServiceException("主裁判尚未确认，总裁无法操作");
		}

		if (result.getScoreStatus() >= MartialResult.SCORE_STATUS_GENERAL_CONFIRMED) {
			throw new ServiceException("该成绩已被总裁确认，无法重复操作");
		}

		// 确定最终分数（基于主裁判确认的分数）
		BigDecimal baseScore = result.getChiefJudgeScore() != null ? result.getChiefJudgeScore() : result.getTotalScore();
		BigDecimal finalScore = score != null ? score : baseScore;

		// 验证分数范围（如果有修改）
		if (score != null && baseScore != null) {
			BigDecimal minAllowed = baseScore.subtract(new BigDecimal("0.050"));
			BigDecimal maxAllowed = baseScore.add(new BigDecimal("0.050"));
			if (score.compareTo(minAllowed) < 0 || score.compareTo(maxAllowed) > 0) {
				throw new ServiceException("修改分数只能在主裁判确认分数±0.050范围内");
			}
		}

		// 更新总裁确认信息
		result.setGeneralJudgeScore(finalScore);
		result.setGeneralJudgeId(generalJudgeId);
		result.setGeneralJudgeTime(LocalDateTime.now());
		result.setGeneralJudgeNote(note);
		result.setScoreStatus(MartialResult.SCORE_STATUS_GENERAL_CONFIRMED);

		// 更新最终得分
		result.setFinalScore(finalScore);

		boolean success = this.updateById(result);

		log.info("总裁确认成绩 - 成绩ID:{}, 总裁ID:{}, 主裁判分数:{}, 确认分数:{}, 备注:{}",
			resultId, generalJudgeId, baseScore, finalScore, note);

		return success;
	}

	/**
	 * 获取待主裁判确认的成绩列表
	 * 
	 * @param venueId 场地ID
	 * @return 成绩列表
	 */
	public List<MartialResult> getPendingChiefConfirmList(Long venueId) {
		QueryWrapper<MartialResult> wrapper = new QueryWrapper<>();
		wrapper.eq("venue_id", venueId);
		wrapper.eq("is_deleted", 0);
		wrapper.and(w -> w.isNull("score_status").or().eq("score_status", MartialResult.SCORE_STATUS_JUDGING));
		wrapper.orderByAsc("create_time");
		return this.list(wrapper);
	}

	/**
	 * 获取待总裁确认的成绩列表
	 * 
	 * @param competitionId 比赛ID（总裁可以看所有场地）
	 * @return 成绩列表
	 */
	@Override
	public List<MartialResult> getPendingGeneralConfirmList(Long competitionId) {
		QueryWrapper<MartialResult> wrapper = new QueryWrapper<>();
		wrapper.eq("competition_id", competitionId);
		wrapper.eq("is_deleted", 0);
		wrapper.eq("score_status", MartialResult.SCORE_STATUS_CHIEF_CONFIRMED);
		wrapper.orderByAsc("create_time");
		List<MartialResult> results = this.list(wrapper);
		
		// 填充选手信息
		for (MartialResult result : results) {
			if (result.getAthleteId() != null) {
				MartialAthlete athlete = athleteService.getById(result.getAthleteId());
				if (athlete != null) {
					result.setPlayerName(athlete.getPlayerName());
					result.setTeamName(athlete.getTeamName());
				}
			}
		}
		
		return results;
	}

	/**
	 * 获取已总裁确认的成绩列表
	 */
	@Override
	public List<MartialResult> getConfirmedGeneralList(Long competitionId) {
		QueryWrapper<MartialResult> wrapper = new QueryWrapper<>();
		wrapper.eq("competition_id", competitionId);
		wrapper.eq("is_deleted", 0);
		wrapper.eq("score_status", MartialResult.SCORE_STATUS_GENERAL_CONFIRMED);
		wrapper.orderByDesc("general_judge_time");
		List<MartialResult> results = this.list(wrapper);
		
		// 填充选手信息
		for (MartialResult result : results) {
			if (result.getAthleteId() != null) {
				MartialAthlete athlete = athleteService.getById(result.getAthleteId());
				if (athlete != null) {
					result.setPlayerName(athlete.getPlayerName());
					result.setTeamName(athlete.getTeamName());
				}
			}
		}
		
		return results;
	}

}

