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.core.metadata.IPage;
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.excel.AthleteExportExcel;
import org.springblade.modules.martial.pojo.entity.MartialAthlete;
import org.springblade.modules.martial.mapper.MartialAthleteMapper;
import org.springblade.modules.martial.pojo.entity.MartialJudgeInvite;
import org.springblade.modules.martial.pojo.entity.MartialScheduleAthlete;
import org.springblade.modules.martial.pojo.entity.MartialScore;
import org.springblade.modules.martial.pojo.vo.MartialAthleteVO;
import org.springblade.modules.martial.pojo.vo.MiniAthleteAdminVO;
import org.springblade.modules.martial.pojo.vo.MiniAthleteScoreVO;
import org.springblade.modules.martial.service.IMartialAthleteService;
import org.springblade.modules.martial.service.IMartialJudgeInviteService;
import org.springblade.modules.martial.service.IMartialScheduleAthleteService;
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.util.List;
import java.util.stream.Collectors;

/**
 * Athlete 服务实现类
 *
 * @author BladeX
 */
@Slf4j
@Service
public class MartialAthleteServiceImpl extends ServiceImpl<MartialAthleteMapper, MartialAthlete> implements IMartialAthleteService {

	@Autowired
	private IMartialScheduleAthleteService scheduleAthleteService;

	@Autowired
	private IMartialScoreService scoreService;

	@Autowired
	private IMartialJudgeInviteService judgeInviteService;

	/**
	 * 分页查询参赛选手（包含关联字段）
	 *
	 * @param page 分页对象
	 * @param athlete 查询条件
	 * @return 参赛选手VO分页数据
	 */
	@Override
	public IPage<MartialAthleteVO> selectAthleteVOPage(IPage<MartialAthleteVO> page, MartialAthlete athlete) {
		return baseMapper.selectAthleteVOPage(page, athlete);
	}

	/**
	 * Task 2.1: 运动员签到检录
	 *
	 * @param athleteId 运动员ID
	 * @param scheduleId 赛程ID
	 */
	@Transactional(rollbackFor = Exception.class)
	public void checkIn(Long athleteId, Long scheduleId) {
		MartialAthlete athlete = this.getById(athleteId);
		if (athlete == null) {
			throw new ServiceException("运动员不存在");
		}

		// 更新运动员状态：待出场(0) → 进行中(1)
		athlete.setCompetitionStatus(1);
		this.updateById(athlete);

		// 更新赛程运动员关联状态
		MartialScheduleAthlete scheduleAthlete = scheduleAthleteService.getOne(
			new QueryWrapper<MartialScheduleAthlete>()
				.eq("schedule_id", scheduleId)
				.eq("athlete_id", athleteId)
				.eq("is_deleted", 0)
		);

		if (scheduleAthlete != null) {
			scheduleAthlete.setIsCompleted(0);  // 未完成
			scheduleAthleteService.updateById(scheduleAthlete);
		}

		log.info("运动员签到成功 - 运动员ID:{}, 姓名:{}, 赛程ID:{}",
			athleteId, athlete.getPlayerName(), scheduleId);
	}

	/**
	 * Task 2.1: 完成比赛
	 *
	 * @param athleteId 运动员ID
	 * @param scheduleId 赛程ID
	 */
	@Transactional(rollbackFor = Exception.class)
	public void completePerformance(Long athleteId, Long scheduleId) {
		MartialAthlete athlete = this.getById(athleteId);
		if (athlete == null) {
			throw new ServiceException("运动员不存在");
		}

		// 更新运动员状态：进行中(1) → 已完成(2)
		athlete.setCompetitionStatus(2);
		this.updateById(athlete);

		// 更新赛程运动员关联状态
		if (scheduleId != null) {
			MartialScheduleAthlete scheduleAthlete = scheduleAthleteService.getOne(
				new QueryWrapper<MartialScheduleAthlete>()
					.eq("schedule_id", scheduleId)
					.eq("athlete_id", athleteId)
					.eq("is_deleted", 0)
			);

			if (scheduleAthlete != null) {
				scheduleAthlete.setIsCompleted(1);  // 已完成
				scheduleAthleteService.updateById(scheduleAthlete);
			}
		}

		log.info("运动员完成比赛 - 运动员ID:{}, 姓名:{}", athleteId, athlete.getPlayerName());
	}

	/**
	 * Task 2.6: 更新比赛状态
	 *
	 * @param athleteId 运动员ID
	 * @param status 状态(0-待出场, 1-进行中, 2-已完成)
	 */
	@Transactional(rollbackFor = Exception.class)
	public void updateCompetitionStatus(Long athleteId, Integer status) {
		// 状态验证
		if (status < 0 || status > 2) {
			throw new ServiceException("无效的比赛状态");
		}

		MartialAthlete athlete = this.getById(athleteId);
		if (athlete == null) {
			throw new ServiceException("运动员不存在");
		}

		// 状态流转验证
		Integer currentStatus = athlete.getCompetitionStatus();
		if (currentStatus != null) {
			// 不允许从已完成(2)回退到其他状态
			if (currentStatus == 2 && status < 2) {
				throw new ServiceException("已完成的比赛不能回退状态");
			}
			// 不允许跳过状态（必须按顺序：0 → 1 → 2）
			if (status - currentStatus > 1) {
				throw new ServiceException("比赛状态不能跳跃变更");
			}
		}

		athlete.setCompetitionStatus(status);
		this.updateById(athlete);

		log.info("更新比赛状态 - 运动员ID:{}, 姓名:{}, 状态: {} → {}",
			athleteId, athlete.getPlayerName(), currentStatus, status);
	}

	/**
	 * Task 3.2: 导出运动员名单
	 *
	 * @param competitionId 赛事ID
	 * @return 导出数据列表
	 */
	@Override
	public List<AthleteExportExcel> exportAthletes(Long competitionId) {
		List<MartialAthlete> athletes = this.list(
			new QueryWrapper<MartialAthlete>()
				.eq("competition_id", competitionId)
				.eq("is_deleted", 0)
				.orderByAsc("player_no")
		);

		return athletes.stream().map(athlete -> {
			AthleteExportExcel excel = new AthleteExportExcel();
			excel.setAthleteCode(athlete.getPlayerNo());
			excel.setPlayerName(athlete.getPlayerName());
			excel.setGender(athlete.getGender() != null ? (athlete.getGender() == 1 ? "男" : "女") : "");
			excel.setAge(athlete.getAge());
			excel.setTeamName(athlete.getTeamName());
			excel.setPhone(athlete.getContactPhone());

			// 项目名称 - 通过projectId查询获取
			String projectNames = "";
			if (athlete.getProjectId() != null) {
				// TODO: 如果需要支持多项目，应从关联表查询
				// 当前简化处理：直接留空或通过category字段
				projectNames = athlete.getCategory() != null ? athlete.getCategory() : "";
			}
			excel.setProjects(projectNames);

			// 比赛状态
			if (athlete.getCompetitionStatus() != null) {
				switch (athlete.getCompetitionStatus()) {
					case 0: excel.setCompetitionStatus("待出场"); break;
					case 1: excel.setCompetitionStatus("进行中"); break;
					case 2: excel.setCompetitionStatus("已完成"); break;
					default: excel.setCompetitionStatus("未知");
				}
			}

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

	/**
	 * 小程序接口：获取选手列表（普通评委）
	 *
	 * @param judgeId 评委ID
	 * @param venueId 场地ID
	 * @param projectId 项目ID
	 * @return 选手列表（含我的评分）
	 */
	@Override
	public List<MiniAthleteScoreVO> getAthletesWithMyScore(Long judgeId, Long venueId, Long projectId) {
		// 查询该场地+项目的所有选手
		LambdaQueryWrapper<MartialAthlete> athleteQuery = new LambdaQueryWrapper<>();
		athleteQuery.eq(MartialAthlete::getProjectId, projectId);
		athleteQuery.eq(MartialAthlete::getIsDeleted, 0);
		athleteQuery.orderByAsc(MartialAthlete::getPlayerNo);

		List<MartialAthlete> athletes = this.list(athleteQuery);

		// 查询该评委对这些选手的评分
		List<Long> athleteIds = athletes.stream()
			.map(MartialAthlete::getId)
			.collect(Collectors.toList());

		List<MartialScore> myScores = List.of();
		if (!athleteIds.isEmpty()) {
			LambdaQueryWrapper<MartialScore> scoreQuery = new LambdaQueryWrapper<>();
			scoreQuery.eq(MartialScore::getJudgeId, judgeId);
			scoreQuery.in(MartialScore::getAthleteId, athleteIds);
			scoreQuery.eq(MartialScore::getIsDeleted, 0);
			myScores = scoreService.list(scoreQuery);
		}

		// 构造返回VO
		List<MartialScore> finalMyScores = myScores;
		return athletes.stream().map(athlete -> {
			MiniAthleteScoreVO vo = new MiniAthleteScoreVO();
			vo.setAthleteId(athlete.getId());
			vo.setName(athlete.getPlayerName());
			vo.setIdCard(athlete.getIdCard());
			vo.setTeam(athlete.getTeamName());
			vo.setNumber(athlete.getPlayerNo());
			vo.setTotalScore(athlete.getTotalScore());

			// 查找我的评分
			MartialScore myScore = finalMyScores.stream()
				.filter(s -> s.getAthleteId().equals(athlete.getId()))
				.findFirst()
				.orElse(null);

			if (myScore != null) {
				vo.setScored(true);
				vo.setMyScore(myScore.getScore());
			} else {
				vo.setScored(false);
				vo.setMyScore(null);
			}

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

	/**
	 * 小程序接口：获取选手列表（裁判长）
	 *
	 * @param competitionId 比赛ID
	 * @param venueId 场地ID
	 * @param projectId 项目ID
	 * @return 选手列表（含评分统计）
	 */
	@Override
	public List<MiniAthleteAdminVO> getAthletesForAdmin(Long competitionId, Long venueId, Long projectId) {
		// 查询该场地+项目的所有选手
		LambdaQueryWrapper<MartialAthlete> athleteQuery = new LambdaQueryWrapper<>();
		athleteQuery.eq(MartialAthlete::getCompetitionId, competitionId);
		athleteQuery.eq(MartialAthlete::getProjectId, projectId);
		athleteQuery.eq(MartialAthlete::getIsDeleted, 0);
		athleteQuery.orderByAsc(MartialAthlete::getPlayerNo);

		List<MartialAthlete> athletes = this.list(athleteQuery);

		// 查询该比赛+场地+项目的评委总数
		LambdaQueryWrapper<MartialJudgeInvite> inviteQuery = new LambdaQueryWrapper<>();
		inviteQuery.eq(MartialJudgeInvite::getCompetitionId, competitionId);
		inviteQuery.eq(MartialJudgeInvite::getVenueId, venueId);
		inviteQuery.eq(MartialJudgeInvite::getRole, "judge"); // 只统计普通评委
		inviteQuery.eq(MartialJudgeInvite::getIsDeleted, 0);
		long totalJudgeCount = judgeInviteService.count(inviteQuery);

		// 查询所有选手的评分
		List<Long> athleteIds = athletes.stream()
			.map(MartialAthlete::getId)
			.collect(Collectors.toList());

		List<MartialScore> allScores = List.of();
		if (!athleteIds.isEmpty()) {
			LambdaQueryWrapper<MartialScore> scoreQuery = new LambdaQueryWrapper<>();
			scoreQuery.in(MartialScore::getAthleteId, athleteIds);
			scoreQuery.eq(MartialScore::getIsDeleted, 0);
			allScores = scoreService.list(scoreQuery);
		}

		// 构造返回VO
		List<MartialScore> finalAllScores = allScores;
		return athletes.stream().map(athlete -> {
			MiniAthleteAdminVO vo = new MiniAthleteAdminVO();
			vo.setAthleteId(athlete.getId());
			vo.setName(athlete.getPlayerName());
			vo.setIdCard(athlete.getIdCard());
			vo.setTeam(athlete.getTeamName());
			vo.setNumber(athlete.getPlayerNo());
			vo.setTotalScore(athlete.getTotalScore());

			// 统计该选手的评分数量
			long judgeCount = finalAllScores.stream()
				.filter(s -> s.getAthleteId().equals(athlete.getId()))
				.count();

			vo.setJudgeCount((int) judgeCount);
			vo.setTotalJudgeCount((int) totalJudgeCount);

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

}
