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

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springblade.modules.martial.excel.ScheduleExportExcel;
import org.springblade.modules.martial.mapper.MartialScheduleDetailMapper;
import org.springblade.modules.martial.mapper.MartialScheduleGroupMapper;
import org.springblade.modules.martial.mapper.MartialScheduleParticipantMapper;
import org.springblade.modules.martial.pojo.dto.CompetitionGroupDTO;
import org.springblade.modules.martial.pojo.dto.ParticipantDTO;
import org.springblade.modules.martial.pojo.dto.SaveScheduleDraftDTO;
import org.springblade.modules.martial.pojo.dto.ScheduleResultDTO;
import org.springblade.modules.martial.pojo.entity.*;
import org.springblade.modules.martial.pojo.vo.ScheduleGroupDetailVO;
import org.springblade.modules.martial.mapper.MartialScheduleMapper;
import org.springblade.modules.martial.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Schedule 服务实现类
 *
 * @author BladeX
 */
@Service
public class MartialScheduleServiceImpl extends ServiceImpl<MartialScheduleMapper, MartialSchedule> implements IMartialScheduleService {

	@Autowired
	private IMartialScheduleAthleteService scheduleAthleteService;

	@Autowired
	private IMartialAthleteService athleteService;

	@Autowired
	private IMartialProjectService projectService;

	@Autowired
	private IMartialVenueService venueService;

	@Autowired
	private MartialScheduleGroupMapper scheduleGroupMapper;

	@Autowired
	private MartialScheduleDetailMapper scheduleDetailMapper;

	@Autowired
	private MartialScheduleParticipantMapper scheduleParticipantMapper;

	/**
	 * Task 3.3: 导出赛程表
	 *
	 * @param competitionId 赛事ID
	 * @return 导出数据列表
	 */
	@Override
	public List<ScheduleExportExcel> exportSchedule(Long competitionId) {
		List<ScheduleExportExcel> exportList = new ArrayList<>();

		// 使用与 getScheduleResult 相同的数据源
		List<ScheduleGroupDetailVO> details = scheduleGroupMapper.selectScheduleGroupDetails(competitionId);

		if (details.isEmpty()) {
			return exportList;
		}

		// 按分组ID分组，然后按 displayOrder 排序
		Map<Long, List<ScheduleGroupDetailVO>> groupMap = details.stream()
			.collect(Collectors.groupingBy(ScheduleGroupDetailVO::getGroupId));

		// 获取分组的排序顺序
		List<Long> sortedGroupIds = details.stream()
			.collect(Collectors.toMap(
				ScheduleGroupDetailVO::getGroupId,
				d -> d.getDisplayOrder() != null ? d.getDisplayOrder() : 999,
				(a, b) -> a
			))
			.entrySet().stream()
			.sorted(Map.Entry.comparingByValue())
			.map(Map.Entry::getKey)
			.collect(Collectors.toList());

		// 按排序顺序遍历分组
		for (Long groupId : sortedGroupIds) {
			List<ScheduleGroupDetailVO> groupDetails = groupMap.get(groupId);
			if (groupDetails == null || groupDetails.isEmpty()) {
				continue;
			}

			ScheduleGroupDetailVO firstDetail = groupDetails.get(0);

			// 过滤出有参赛者的记录，并按出场顺序排序
			List<ScheduleGroupDetailVO> participants = groupDetails.stream()
				.filter(d -> d.getParticipantId() != null)
				.sorted(Comparator.comparing(d -> d.getPerformanceOrder() != null ? d.getPerformanceOrder() : 999))
				.collect(Collectors.toList());

			if (participants.isEmpty()) {
				// 没有参赛者，创建一条基础记录
				ScheduleExportExcel excel = new ScheduleExportExcel();
				excel.setScheduleDate(firstDetail.getScheduleDate() != null ? firstDetail.getScheduleDate() : "");
				excel.setTimeSlot(firstDetail.getTimeSlot());
				excel.setVenueName(firstDetail.getVenueName());
				excel.setProjectName(firstDetail.getGroupName());
				excel.setCategory(firstDetail.getCategory());
				excel.setStatus("completed".equals(firstDetail.getScheduleStatus()) ? "已完成" : "草稿");
				exportList.add(excel);
			} else {
				// 为每个参赛者创建导出记录
				for (ScheduleGroupDetailVO detail : participants) {
					ScheduleExportExcel excel = new ScheduleExportExcel();
					excel.setScheduleDate(detail.getScheduleDate() != null ? detail.getScheduleDate() : "");
					excel.setTimeSlot(detail.getTimeSlot());
					excel.setVenueName(detail.getVenueName());
					excel.setProjectName(detail.getGroupName());
					excel.setCategory(detail.getCategory());
					excel.setAthleteName(detail.getPlayerName());
					excel.setTeamName(detail.getOrganization());
					excel.setSortOrder(detail.getPerformanceOrder());
					excel.setStatus(detail.getCheckInStatus() != null ? detail.getCheckInStatus() : "未签到");
					exportList.add(excel);
				}
			}
		}

		return exportList;
	}

	/**
	 * 获取赛程编排结果（优化版本：使用单次JOIN查询）
	 *
	 * @param competitionId 赛事ID
	 * @return 赛程编排结果
	 */
	@Override
	public ScheduleResultDTO getScheduleResult(Long competitionId) {
		ScheduleResultDTO result = new ScheduleResultDTO();

		// 使用优化的一次性JOIN查询获取所有数据
		List<ScheduleGroupDetailVO> details = scheduleGroupMapper.selectScheduleGroupDetails(competitionId);

		if (details.isEmpty()) {
			result.setIsDraft(true);
			result.setIsCompleted(false);
			result.setCompetitionGroups(new ArrayList<>());
			return result;
		}

		// 按分组ID分组数据
		Map<Long, List<ScheduleGroupDetailVO>> groupMap = details.stream()
			.collect(Collectors.groupingBy(ScheduleGroupDetailVO::getGroupId));

		// 检查编排状态
		boolean isCompleted = details.stream()
			.anyMatch(d -> "completed".equals(d.getScheduleStatus()));
		boolean isDraft = !isCompleted;

		result.setIsDraft(isDraft);
		result.setIsCompleted(isCompleted);

		// 组装数据
		List<CompetitionGroupDTO> groupDTOs = new ArrayList<>();
		for (Map.Entry<Long, List<ScheduleGroupDetailVO>> entry : groupMap.entrySet()) {
			List<ScheduleGroupDetailVO> groupDetails = entry.getValue();
			if (groupDetails.isEmpty()) {
				continue;
			}

			// 获取第一条记录作为分组信息（同一分组的记录，分组信息是相同的）
			ScheduleGroupDetailVO firstDetail = groupDetails.get(0);

			CompetitionGroupDTO groupDTO = new CompetitionGroupDTO();
			groupDTO.setId(firstDetail.getGroupId());
			groupDTO.setTitle(firstDetail.getGroupName());
			groupDTO.setCode(firstDetail.getCategory());

			// 设置类型
			if (firstDetail.getProjectType() != null) {
				switch (firstDetail.getProjectType()) {
					case 1:
						groupDTO.setType("单人");
						break;
					case 2:
						groupDTO.setType("集体");
						break;
					default:
						groupDTO.setType("其他");
						break;
				}
			}

			// 设置队伍数量
			if (firstDetail.getTotalTeams() != null && firstDetail.getTotalTeams() > 0) {
				groupDTO.setCount(firstDetail.getTotalTeams() + "队");
			} else if (firstDetail.getTotalParticipants() != null) {
				groupDTO.setCount(firstDetail.getTotalParticipants() + "人");
			}

			// 设置场地和时间段信息
			groupDTO.setVenueId(firstDetail.getVenueId());
			groupDTO.setVenueName(firstDetail.getVenueName());
			groupDTO.setTimeSlot(firstDetail.getTimeSlot());
			groupDTO.setTimeSlotIndex(firstDetail.getTimeSlotIndex() != null ? firstDetail.getTimeSlotIndex() : 0); // 直接从数据库读取

			// 获取参赛者列表
			List<ParticipantDTO> participantDTOs = groupDetails.stream()
				.filter(d -> d.getParticipantId() != null) // 过滤掉没有参赛者的记录
				.map(d -> {
					ParticipantDTO dto = new ParticipantDTO();
					dto.setId(d.getParticipantId());
					dto.setSchoolUnit(d.getOrganization());
					dto.setStatus(d.getCheckInStatus() != null ? d.getCheckInStatus() : "未签到");
					dto.setSortOrder(d.getPerformanceOrder());
					dto.setPlayerName(d.getPlayerName());
					return dto;
				})
				.collect(Collectors.toList());

			groupDTO.setParticipants(participantDTOs);
			groupDTOs.add(groupDTO);
		}

		// 按 displayOrder 排序
		groupDTOs.sort(Comparator.comparing(g -> {
			ScheduleGroupDetailVO detail = details.stream()
				.filter(d -> d.getGroupId().equals(g.getId()))
				.findFirst()
				.orElse(null);
			return detail != null ? detail.getDisplayOrder() : 999;
		}));

		result.setCompetitionGroups(groupDTOs);
		return result;
	}

	/**
	 * 保存编排草稿
	 *
	 * @param dto 编排草稿数据
	 * @return 是否成功
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean saveDraftSchedule(SaveScheduleDraftDTO dto) {
		if (dto.getCompetitionGroups() == null || dto.getCompetitionGroups().isEmpty()) {
			return false;
		}

		for (CompetitionGroupDTO groupDTO : dto.getCompetitionGroups()) {
			// 1. 更新或创建编排明细
			MartialScheduleDetail detail = scheduleDetailMapper.selectOne(
				new QueryWrapper<MartialScheduleDetail>()
					.eq("schedule_group_id", groupDTO.getId())
					.eq("is_deleted", 0)
					.last("LIMIT 1")
			);

			if (detail == null) {
				detail = new MartialScheduleDetail();
				detail.setScheduleGroupId(groupDTO.getId());
				detail.setCompetitionId(dto.getCompetitionId());
			}

			detail.setVenueId(groupDTO.getVenueId());
			detail.setVenueName(groupDTO.getVenueName());
			detail.setTimeSlot(groupDTO.getTimeSlot());

			// 解析日期
			if (groupDTO.getTimeSlot() != null && groupDTO.getTimeSlot().contains("年")) {
				try {
					String dateStr = groupDTO.getTimeSlot().split(" ")[0];
					dateStr = dateStr.replace("年", "-").replace("月", "-").replace("日", "");
					detail.setScheduleDate(LocalDate.parse(dateStr));
				} catch (Exception e) {
					// 日期解析失败，忽略
				}
			}

			if (detail.getId() == null) {
				scheduleDetailMapper.insert(detail);
			} else {
				scheduleDetailMapper.updateById(detail);
			}

			// 2. 更新参赛者信息
			if (groupDTO.getParticipants() != null) {
				for (ParticipantDTO participantDTO : groupDTO.getParticipants()) {
					MartialScheduleParticipant participant = scheduleParticipantMapper.selectById(participantDTO.getId());
					if (participant != null) {
						participant.setCheckInStatus(participantDTO.getStatus());
						participant.setPerformanceOrder(participantDTO.getSortOrder());
						participant.setScheduleStatus("draft");
						scheduleParticipantMapper.updateById(participant);
					}
				}
			}
		}

		return true;
	}

	/**
	 * 完成编排并锁定
	 *
	 * @param competitionId 赛事ID
	 * @return 是否成功
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean saveAndLockSchedule(Long competitionId) {
		// 1. 查询所有分组
		List<MartialScheduleGroup> groups = scheduleGroupMapper.selectList(
			new QueryWrapper<MartialScheduleGroup>()
				.eq("competition_id", competitionId)
				.eq("is_deleted", 0)
		);

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

		// 2. 获取所有分组ID
		List<Long> groupIds = groups.stream().map(MartialScheduleGroup::getId).collect(Collectors.toList());

		// 3. 更新所有参赛者的编排状态为completed
		List<MartialScheduleParticipant> participants = scheduleParticipantMapper.selectList(
			new QueryWrapper<MartialScheduleParticipant>()
				.in("schedule_group_id", groupIds)
				.eq("is_deleted", 0)
		);

		for (MartialScheduleParticipant participant : participants) {
			participant.setScheduleStatus("completed");
			scheduleParticipantMapper.updateById(participant);
		}

		return true;
	}

	/**
	 * 根据时间段字符串计算 timeSlotIndex
	 * 按照时间从早到晚分配索引: 08:30=0, 13:30=1, 其他时间按字符串顺序排序
	 *
	 * @param timeSlot 时间段字符串 (如 "08:30", "13:30")
	 * @return 时间段索引
	 */
	private int calculateTimeSlotIndex(String timeSlot) {
		if (timeSlot == null || timeSlot.trim().isEmpty()) {
			return 0;
		}

		// 标准时间段映射
		switch (timeSlot.trim()) {
			case "08:30":
				return 0; // 上午场
			case "13:30":
				return 1; // 下午场
			default:
				// 其他时间段,尝试解析并分配索引
				// 如果是上午(< 12:00)返回0,下午(>= 12:00)返回1
				try {
					String[] parts = timeSlot.trim().split(":");
					if (parts.length >= 1) {
						int hour = Integer.parseInt(parts[0]);
						return hour < 12 ? 0 : 1;
					}
				} catch (Exception e) {
					// 解析失败,返回默认值
				}
				return 0;
		}
	}

	/**
	 * 移动赛程分组到指定场地和时间段
	 *
	 * @param dto 移动请求数据
	 * @return 是否成功
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean moveScheduleGroup(org.springblade.modules.martial.pojo.dto.MoveScheduleGroupDTO dto) {
		// 1. 查询分组信息
		MartialScheduleGroup group = scheduleGroupMapper.selectById(dto.getGroupId());
		if (group == null) {
			throw new RuntimeException("分组不存在");
		}

		// 2. 查询该分组的详情记录
		List<MartialScheduleDetail> details = scheduleDetailMapper.selectList(
			new QueryWrapper<MartialScheduleDetail>()
				.eq("schedule_group_id", dto.getGroupId())
				.eq("is_deleted", 0)
		);

		if (details.isEmpty()) {
			throw new RuntimeException("分组详情不存在");
		}

		// 3. 查询目标场地信息
		MartialVenue targetVenue = venueService.getById(dto.getTargetVenueId());
		if (targetVenue == null) {
			throw new RuntimeException("目标场地不存在");
		}

		// 4. 根据时间段索引计算日期和时间
		// 假设: 0=第1天上午, 1=第1天下午, 2=第2天上午, 3=第2天下午...
		// 需要从赛事信息中获取起始日期
		int dayOffset = dto.getTargetTimeSlotIndex() / 2; // 每天2个时段
		boolean isAfternoon = dto.getTargetTimeSlotIndex() % 2 == 1;
		String timeSlot = isAfternoon ? "13:30" : "08:30";

		// 获取赛事起始日期(从第一个detail中获取)
		LocalDate baseDate = details.get(0).getScheduleDate();
		if (baseDate == null) {
			throw new RuntimeException("无法确定赛事起始日期");
		}

		// 计算目标日期(从起始日期开始,加上dayOffset天的偏移)
		// 如果当前detail的日期早于base date,需要调整
		LocalDate minDate = details.stream()
			.map(MartialScheduleDetail::getScheduleDate)
			.filter(Objects::nonNull)
			.min(LocalDate::compareTo)
			.orElse(baseDate);

		LocalDate targetDate = minDate.plusDays(dayOffset);

		// 5. 更新所有detail记录
		for (MartialScheduleDetail detail : details) {
			detail.setVenueId(dto.getTargetVenueId());
			detail.setVenueName(targetVenue.getVenueName());
			detail.setScheduleDate(targetDate);
			detail.setTimeSlot(timeSlot);
			detail.setTimeSlotIndex(dto.getTargetTimeSlotIndex());
			scheduleDetailMapper.updateById(detail);
		}

		return true;
	}

	@Override
	public org.springblade.modules.martial.pojo.vo.DispatchDataVO getDispatchData(Long competitionId, Long venueId, Integer timeSlotIndex) {
		// 1. 查询指定场地和时间段的编排明细
		List<MartialScheduleDetail> details = scheduleDetailMapper.selectList(
			new QueryWrapper<MartialScheduleDetail>()
				.eq("competition_id", competitionId)
				.eq("venue_id", venueId)
				.eq("time_slot_index", timeSlotIndex)
				.eq("is_deleted", 0)
				.orderByAsc("sort_order")
		);

		if (details.isEmpty()) {
			// 返回空数据
			org.springblade.modules.martial.pojo.vo.DispatchDataVO vo = new org.springblade.modules.martial.pojo.vo.DispatchDataVO();
			vo.setGroups(new ArrayList<>());
			return vo;
		}

		// 2. 构建返回数据
		List<org.springblade.modules.martial.pojo.vo.DispatchDataVO.DispatchGroup> groups = new ArrayList<>();

		for (MartialScheduleDetail detail : details) {
			// 查询分组信息
			MartialScheduleGroup group = scheduleGroupMapper.selectById(detail.getScheduleGroupId());
			if (group == null) {
				continue;
			}

			// 查询该明细下的所有参赛者
			List<MartialScheduleParticipant> participants = scheduleParticipantMapper.selectList(
				new QueryWrapper<MartialScheduleParticipant>()
					.eq("schedule_detail_id", detail.getId())
					.eq("is_deleted", 0)
					.orderByAsc("performance_order")
			);

			// 转换为VO
			org.springblade.modules.martial.pojo.vo.DispatchDataVO.DispatchGroup groupVO =
				new org.springblade.modules.martial.pojo.vo.DispatchDataVO.DispatchGroup();
			groupVO.setGroupId(group.getId());
			groupVO.setGroupName(group.getGroupName());
			groupVO.setDetailId(detail.getId());
			groupVO.setProjectType(group.getProjectType());

			List<org.springblade.modules.martial.pojo.vo.DispatchDataVO.DispatchParticipant> participantVOs =
				participants.stream().map(p -> {
					org.springblade.modules.martial.pojo.vo.DispatchDataVO.DispatchParticipant pVO =
						new org.springblade.modules.martial.pojo.vo.DispatchDataVO.DispatchParticipant();
					pVO.setId(p.getId());
					pVO.setParticipantId(p.getParticipantId());
					pVO.setOrganization(p.getOrganization());
					pVO.setPlayerName(p.getPlayerName());
					pVO.setProjectName(p.getProjectName());
					pVO.setCategory(p.getCategory());
					pVO.setPerformanceOrder(p.getPerformanceOrder());
					return pVO;
				}).collect(Collectors.toList());

			groupVO.setParticipants(participantVOs);
			groups.add(groupVO);
		}

		org.springblade.modules.martial.pojo.vo.DispatchDataVO result =
			new org.springblade.modules.martial.pojo.vo.DispatchDataVO();
		result.setGroups(groups);
		return result;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean adjustOrder(org.springblade.modules.martial.pojo.dto.AdjustOrderDTO dto) {
		// 1. 查询当前参赛者
		MartialScheduleParticipant current = scheduleParticipantMapper.selectById(dto.getParticipantId());
		if (current == null) {
			throw new RuntimeException("参赛者不存在");
		}

		// 2. 查询同一明细下的所有参赛者
		List<MartialScheduleParticipant> participants = scheduleParticipantMapper.selectList(
			new QueryWrapper<MartialScheduleParticipant>()
				.eq("schedule_detail_id", dto.getDetailId())
				.eq("is_deleted", 0)
				.orderByAsc("performance_order")
		);

		// 3. 根据动作调整顺序
		int currentIndex = -1;
		for (int i = 0; i < participants.size(); i++) {
			if (participants.get(i).getId().equals(dto.getParticipantId())) {
				currentIndex = i;
				break;
			}
		}

		if (currentIndex == -1) {
			throw new RuntimeException("未找到参赛者");
		}

		// 4. 执行调整
		if ("move_up".equals(dto.getAction())) {
			// 上移
			if (currentIndex == 0) {
				throw new RuntimeException("已经是第一个，无法上移");
			}
			// 交换位置
			Collections.swap(participants, currentIndex, currentIndex - 1);
		} else if ("move_down".equals(dto.getAction())) {
			// 下移
			if (currentIndex == participants.size() - 1) {
				throw new RuntimeException("已经是最后一个，无法下移");
			}
			// 交换位置
			Collections.swap(participants, currentIndex, currentIndex + 1);
		} else if ("swap".equals(dto.getAction())) {
			// 交换到指定位置
			if (dto.getTargetOrder() == null || dto.getTargetOrder() < 1 || dto.getTargetOrder() > participants.size()) {
				throw new RuntimeException("目标顺序无效");
			}
			int targetIndex = dto.getTargetOrder() - 1;
			Collections.swap(participants, currentIndex, targetIndex);
		}

		// 5. 更新所有参赛者的顺序
		for (int i = 0; i < participants.size(); i++) {
			MartialScheduleParticipant p = participants.get(i);
			p.setPerformanceOrder(i + 1);
			scheduleParticipantMapper.updateById(p);
		}

		return true;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean saveDispatch(org.springblade.modules.martial.pojo.dto.SaveDispatchDTO dto) {
		if (dto.getAdjustments() == null || dto.getAdjustments().isEmpty()) {
			return true;
		}

		// 批量更新所有参赛者的出场顺序
		for (org.springblade.modules.martial.pojo.dto.SaveDispatchDTO.DetailAdjustment adjustment : dto.getAdjustments()) {
			for (org.springblade.modules.martial.pojo.dto.SaveDispatchDTO.ParticipantOrder po : adjustment.getParticipants()) {
				MartialScheduleParticipant participant = scheduleParticipantMapper.selectById(po.getId());
				if (participant != null) {
					participant.setPerformanceOrder(po.getPerformanceOrder());
					scheduleParticipantMapper.updateById(participant);
				}
			}
		}

		return true;
	}

}
