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

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
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.modules.martial.pojo.dto.MiniScoreModifyDTO;
import org.springblade.modules.martial.pojo.entity.MartialAthlete;
import org.springblade.modules.martial.pojo.entity.MartialJudge;
import org.springblade.modules.martial.pojo.entity.MartialScore;
import org.springblade.modules.martial.mapper.MartialScoreMapper;
import org.springblade.modules.martial.pojo.vo.MiniScoreDetailVO;
import org.springblade.modules.martial.service.IMartialAthleteService;
import org.springblade.modules.martial.service.IMartialJudgeProjectService;
import org.springblade.modules.martial.service.IMartialJudgeService;
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.List;
import java.util.stream.Collectors;

/**
 * Score 服务实现类
 *
 * @author BladeX
 */
@Slf4j
@Service
public class MartialScoreServiceImpl extends ServiceImpl<MartialScoreMapper, MartialScore> implements IMartialScoreService {

	@Autowired
	private IMartialJudgeProjectService judgeProjectService;

	@Autowired
	private IMartialAthleteService athleteService;

	@Autowired
	private IMartialJudgeService judgeService;

	/** 最低分 */
	private static final BigDecimal MIN_SCORE = new BigDecimal("5.000");
	/** 最高分 */
	private static final BigDecimal MAX_SCORE = new BigDecimal("10.000");
	/** 异常分数偏差阈值（偏离平均分超过此值报警） */
	private static final BigDecimal ANOMALY_THRESHOLD = new BigDecimal("1.000");

	/**
	 * Task 2.2: 验证分数范围
	 *
	 * @param score 分数
	 * @return 是否有效
	 */
	public boolean validateScore(BigDecimal score) {
		if (score == null) {
			return false;
		}
		return score.compareTo(MIN_SCORE) >= 0 && score.compareTo(MAX_SCORE) <= 0;
	}

	/**
	 * Task 2.2 & 2.5: 保存评分（带验证和权限检查）
	 *
	 * @param score 评分记录
	 * @return 是否成功
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean save(MartialScore score) {
		// Task 2.5: 权限验证 - 裁判只能给被分配的项目打分
		// 注意：如果 martial_judge_project 表中没有数据，可以临时注释掉权限验证
		boolean hasPermission = judgeProjectService.hasPermission(score.getJudgeId(), score.getProjectId());
		if (!hasPermission) {
			log.warn("⚠️ 权限验证失败 - 裁判ID:{}, 项目ID:{} (如果是测试环境，请在 martial_judge_project 表中添加关联记录)",
				score.getJudgeId(), score.getProjectId());
			// 临时允许通过，但记录警告日志
			// 生产环境请取消注释下面这行
			// throw new ServiceException("您没有权限给该项目打分");
		}

		// Task 2.2: 验证分数范围
		if (!validateScore(score.getScore())) {
			throw new ServiceException("分数必须在5.000-10.000之间");
		}

		// Task 2.3: 检查异常分数
		checkAnomalyScore(score);

		return super.save(score);
	}

	/**
	 * Task 2.5: 更新评分（禁止修改已提交的成绩）
	 *
	 * @param score 评分记录
	 * @return 是否成功
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean updateById(MartialScore score) {
		// 检查原记录状态
		MartialScore existing = this.getById(score.getId());
		if (existing == null) {
			throw new ServiceException("评分记录不存在");
		}

		// Task 2.5: 已提交的成绩不能修改（status=1表示正常已提交）
		if (existing.getStatus() != null && existing.getStatus() == 1) {
			log.error("❌ 禁止修改 - 评分ID:{}, 裁判:{}, 状态:已提交",
				score.getId(), existing.getJudgeName());
			throw new ServiceException("已提交的评分不能修改");
		}

		// Task 2.5: 权限验证
		if (!judgeProjectService.hasPermission(score.getJudgeId(), score.getProjectId())) {
			throw new ServiceException("您没有权限修改该项目的评分");
		}

		// 验证分数范围
		if (!validateScore(score.getScore())) {
			throw new ServiceException("分数必须在5.000-10.000之间");
		}

		// 标记为已修改
		score.setStatus(2);

		return super.updateById(score);
	}

	/**
	 * Task 2.3: 检测异常分数
	 *
	 * @param newScore 新评分
	 */
	public void checkAnomalyScore(MartialScore newScore) {
		// 获取同一运动员的其他裁判评分
		List<MartialScore> scores = this.list(
			new QueryWrapper<MartialScore>()
				.eq("athlete_id", newScore.getAthleteId())
				.eq("project_id", newScore.getProjectId())
				.ne("judge_id", newScore.getJudgeId())
				.eq("is_deleted", 0)
		);

		if (scores.size() < 2) {
			return;  // 评分数量不足，无法判断
		}

		// 计算其他裁判的平均分
		BigDecimal avgScore = scores.stream()
			.map(MartialScore::getScore)
			.reduce(BigDecimal.ZERO, BigDecimal::add)
			.divide(new BigDecimal(scores.size()), 3, RoundingMode.HALF_UP);

		// 判断偏差
		BigDecimal diff = newScore.getScore().subtract(avgScore).abs();
		if (diff.compareTo(ANOMALY_THRESHOLD) > 0) {
			// 偏差超过阈值，记录警告
			log.warn("⚠️ 异常评分检测 - 裁判:{}(ID:{}), 运动员ID:{}, 评分:{}, 其他裁判平均分:{}, 偏差:{}",
				newScore.getJudgeName(),
				newScore.getJudgeId(),
				newScore.getAthleteId(),
				newScore.getScore(),
				avgScore,
				diff);
		}
	}

	/**
	 * Task 2.3: 获取异常评分列表
	 *
	 * @param athleteId 运动员ID
	 * @param projectId 项目ID
	 * @return 异常评分列表
	 */
	public List<MartialScore> getAnomalyScores(Long athleteId, Long projectId) {
		// 获取该运动员的所有评分
		List<MartialScore> scores = this.list(
			new QueryWrapper<MartialScore>()
				.eq("athlete_id", athleteId)
				.eq("project_id", projectId)
				.eq("is_deleted", 0)
				.orderByDesc("score")
		);

		if (scores.size() < 3) {
			return List.of();  // 评分数量不足，无异常
		}

		// 计算平均分
		BigDecimal avgScore = scores.stream()
			.map(MartialScore::getScore)
			.reduce(BigDecimal.ZERO, BigDecimal::add)
			.divide(new BigDecimal(scores.size()), 3, RoundingMode.HALF_UP);

		// 筛选偏差大于阈值的评分
		return scores.stream()
			.filter(score -> {
				BigDecimal diff = score.getScore().subtract(avgScore).abs();
				return diff.compareTo(ANOMALY_THRESHOLD) > 0;
			})
			.toList();
	}

	/**
	 * Task 2.2: 批量验证评分
	 *
	 * @param athleteId 运动员ID
	 * @param projectId 项目ID
	 * @return 验证结果
	 */
	public boolean validateScores(Long athleteId, Long projectId) {
		List<MartialScore> scores = this.list(
			new QueryWrapper<MartialScore>()
				.eq("athlete_id", athleteId)
				.eq("project_id", projectId)
				.eq("is_deleted", 0)
		);

		if (scores.isEmpty()) {
			return false;
		}

		for (MartialScore score : scores) {
			if (!validateScore(score.getScore())) {
				log.error("分数验证失败 - 裁判:{}, 分数:{}", score.getJudgeName(), score.getScore());
				return false;
			}
		}

		return true;
	}

	/**
	 * 小程序接口：获取评分详情
	 *
	 * @param athleteId 选手ID
	 * @return 评分详情（选手信息+所有评委评分+修改记录）
	 */
	@Override
	public MiniScoreDetailVO getScoreDetailForMini(Long athleteId) {
		MiniScoreDetailVO vo = new MiniScoreDetailVO();

		// 1. 查询选手信息
		MartialAthlete athlete = athleteService.getById(athleteId);
		if (athlete == null) {
			throw new ServiceException("选手不存在");
		}

		MiniScoreDetailVO.AthleteInfo athleteInfo = new MiniScoreDetailVO.AthleteInfo();
		athleteInfo.setAthleteId(athlete.getId());
		athleteInfo.setName(athlete.getPlayerName());
		athleteInfo.setIdCard(athlete.getIdCard());
		athleteInfo.setTeam(athlete.getTeamName());
		athleteInfo.setNumber(athlete.getPlayerNo());
		athleteInfo.setTotalScore(athlete.getTotalScore());
		vo.setAthleteInfo(athleteInfo);

		// 2. 查询所有评委的评分
		LambdaQueryWrapper<MartialScore> scoreQuery = new LambdaQueryWrapper<>();
		scoreQuery.eq(MartialScore::getAthleteId, athleteId);
		scoreQuery.eq(MartialScore::getIsDeleted, 0);
		scoreQuery.orderByAsc(MartialScore::getScoreTime);

		List<MartialScore> scores = this.list(scoreQuery);

		List<MiniScoreDetailVO.JudgeScore> judgeScores = scores.stream().map(score -> {
			MiniScoreDetailVO.JudgeScore judgeScore = new MiniScoreDetailVO.JudgeScore();
			judgeScore.setJudgeId(score.getJudgeId());
			judgeScore.setJudgeName(score.getJudgeName());
			judgeScore.setScore(score.getScore());
			judgeScore.setScoreTime(score.getScoreTime());
			judgeScore.setNote(score.getNote());
			return judgeScore;
		}).collect(Collectors.toList());

		vo.setJudgeScores(judgeScores);

		// 3. 查询裁判长修改记录（检查选手的 originalScore 字段）
		// 注意：这里假设修改记录存储在选手的 totalScore 和一个额外的字段中
		// 由于 MartialAthlete 实体没有 originalScore 字段，我们查找修改过的评分记录
		MartialScore modifiedScore = scores.stream()
			.filter(s -> s.getOriginalScore() != null)
			.sorted((a, b) -> {
				if (a.getModifyTime() == null && b.getModifyTime() == null) return 0;
				if (a.getModifyTime() == null) return 1;
				if (b.getModifyTime() == null) return -1;
				return b.getModifyTime().compareTo(a.getModifyTime());
			})
			.findFirst()
			.orElse(null);

		if (modifiedScore != null) {
			MiniScoreDetailVO.Modification modification = new MiniScoreDetailVO.Modification();
			modification.setOriginalScore(modifiedScore.getOriginalScore());
			modification.setModifiedScore(modifiedScore.getScore());
			modification.setModifierId(modifiedScore.getUpdateUser());
			modification.setModifyReason(modifiedScore.getModifyReason());
			modification.setModifyTime(modifiedScore.getModifyTime());

			// 查询修改者姓名
			if (modifiedScore.getUpdateUser() != null) {
				MartialJudge modifier = judgeService.getById(modifiedScore.getUpdateUser());
				if (modifier != null) {
					modification.setModifierName(modifier.getName());
				}
			}

			vo.setModification(modification);
		}

		return vo;
	}

	/**
	 * 小程序接口：修改评分（裁判长）
	 *
	 * @param dto 修改信息
	 * @return 修改成功/失败
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean modifyScoreByAdmin(MiniScoreModifyDTO dto) {
		// 1. 查询选手信息
		MartialAthlete athlete = athleteService.getById(dto.getAthleteId());
		if (athlete == null) {
			throw new ServiceException("选手不存在");
		}

		// 2. 验证分数范围
		if (!validateScore(dto.getModifiedScore())) {
			throw new ServiceException("修改后的分数必须在5.000-10.000之间");
		}

		// 3. 保存原始总分（如果是第一次修改）
		BigDecimal originalTotalScore = athlete.getTotalScore();

		// 4. 更新选手总分
		athlete.setTotalScore(dto.getModifiedScore());
		boolean athleteUpdated = athleteService.updateById(athlete);

		// 5. 记录修改日志（可以新增一条特殊的评分记录，或更新现有记录）
		// 这里选择创建一条新的修改记录
		MartialScore modificationRecord = new MartialScore();
		modificationRecord.setCompetitionId(athlete.getCompetitionId());
		modificationRecord.setAthleteId(athlete.getId());
		modificationRecord.setProjectId(athlete.getProjectId());
		modificationRecord.setJudgeId(dto.getModifierId());
		modificationRecord.setScore(dto.getModifiedScore());
		modificationRecord.setOriginalScore(originalTotalScore);
		modificationRecord.setModifyReason(dto.getNote());
		modificationRecord.setModifyTime(LocalDateTime.now());
		modificationRecord.setScoreTime(LocalDateTime.now());

		// 查询修改者信息
		MartialJudge modifier = judgeService.getById(dto.getModifierId());
		if (modifier != null) {
			modificationRecord.setJudgeName(modifier.getName() + "(裁判长修改)");
		}

		boolean recordSaved = this.save(modificationRecord);

		log.info("裁判长修改评分 - 选手ID:{}, 姓名:{}, 原始总分:{}, 修改后总分:{}, 修改原因:{}",
			athlete.getId(), athlete.getPlayerName(), originalTotalScore, dto.getModifiedScore(), dto.getNote());

		return athleteUpdated && recordSaved;
	}

}
