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

import org.springblade.modules.martial.service.IScheduleExportService;
import org.springblade.modules.martial.service.IScheduleQueryService;
import org.springblade.modules.martial.service.IScheduleArrangeService;
import org.springblade.modules.martial.service.IScheduleDispatchService;
import org.springblade.modules.martial.service.IScheduleStatusService;

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.excel.ScheduleExportExcel2;
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.mapper.MartialAthleteMapper;
import org.springblade.modules.martial.mapper.MartialTeamMemberMapper;
import org.springblade.modules.martial.pojo.entity.MartialAthlete;
import org.springblade.modules.martial.mapper.MartialTeamMapper;
import org.springblade.modules.martial.pojo.entity.MartialTeamMember;
import org.springblade.modules.martial.pojo.dto.CompetitionGroupDTO;
import org.springblade.modules.martial.pojo.entity.MartialTeam;
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 lombok.extern.slf4j.Slf4j;
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
 */
@Slf4j
@Service
public class MartialScheduleServiceImpl extends ServiceImpl<MartialScheduleMapper, MartialSchedule> implements IMartialScheduleService {

	@Autowired
	private IMartialScheduleAthleteService scheduleAthleteService;

	@Autowired
	private IMartialAthleteService athleteService;

	@Autowired
	private IMartialProjectService projectService;

	@Autowired
	private IScheduleExportService scheduleExportService;

	@Autowired
	private IScheduleQueryService scheduleQueryService;

	@Autowired
	private IScheduleArrangeService scheduleArrangeService;

	@Autowired
	private IScheduleDispatchService scheduleDispatchService;

	@Autowired
	private IScheduleStatusService scheduleStatusService;

	@Autowired
	private IMartialVenueService venueService;

	@Autowired
	private MartialScheduleGroupMapper scheduleGroupMapper;

	@Autowired
	private MartialScheduleDetailMapper scheduleDetailMapper;

	@Autowired
	private MartialScheduleParticipantMapper scheduleParticipantMapper;
	@Autowired
	private MartialAthleteMapper athleteMapper;
	@Autowired
	private MartialTeamMemberMapper teamMemberMapper;
	@Autowired
	private MartialTeamMapper teamMapper;

	/**
	 * Task 3.3: 导出赛程表
	 *
	 * @param competitionId 赛事ID
	 * @return 导出数据列表
	 */
	@Override
	public List<ScheduleExportExcel> exportSchedule(Long competitionId) {
		// Delegated to ScheduleExportService
		return scheduleExportService.exportSchedule(competitionId);
	}
	@Override
	public List<ScheduleExportExcel2> exportScheduleTemplate2(Long competitionId, Long venueId) {
		List<ScheduleExportExcel2> exportList = new ArrayList<>();
		List<ScheduleGroupDetailVO> details = scheduleGroupMapper.selectScheduleGroupDetails(competitionId);
		if (details.isEmpty()) {
			return exportList;
		}
		if (venueId != null) {
			details = details.stream().filter(d -> venueId.equals(d.getVenueId())).collect(Collectors.toList());
		}
		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());
		int sequenceNo = 1;
		int tableNoBase = 1101;
		for (Long groupId : sortedGroupIds) {
			List<ScheduleGroupDetailVO> groupDetails = groupMap.get(groupId);
			if (groupDetails == null || groupDetails.isEmpty()) continue;
			ScheduleGroupDetailVO firstDetail = groupDetails.get(0);
			long participantCount = groupDetails.stream().filter(d -> d.getParticipantId() != null).count();
			int durationMinutes = (int) (participantCount * 4);
			ScheduleExportExcel2 excel = new ScheduleExportExcel2();
			excel.setSequenceNo(sequenceNo++);
			excel.setProjectName(firstDetail.getGroupName());
			excel.setParticipantCount((int) participantCount);
			excel.setGroupCount(1);
			excel.setDurationMinutes(durationMinutes);
			excel.setTableNo(String.valueOf(tableNoBase++));
			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()) {
			// 没有编排数据时，从项目和选手表生成初始分组
			return generateInitialScheduleResult(competitionId);
		}

		// 按分组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);
			groupDTO.setEstimatedDuration(firstDetail.getEstimatedDuration());

			// 获取参赛者列表
			boolean isCollective = firstDetail.getProjectType() != null && firstDetail.getProjectType() == 2;
			List<ParticipantDTO> participantDTOs = new ArrayList<>();
			for (ScheduleGroupDetailVO d : groupDetails) {
				if (d.getParticipantId() == null) continue;
				
				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());
				
				// For collective projects, query team members
				if (isCollective) {
					List<Map<String, Object>> memberList = new ArrayList<>();
					// Step 1: Get athlete record to find team_name
					MartialAthlete participantAthlete = athleteMapper.selectById(d.getParticipantId());
					if (participantAthlete != null && participantAthlete.getTeamName() != null) {
						// Step 2: Find team by team_name
						QueryWrapper<MartialTeam> teamWrapper = new QueryWrapper<>();
						teamWrapper.eq("team_name", participantAthlete.getTeamName());
						teamWrapper.eq("is_deleted", 0);
						MartialTeam team = teamMapper.selectOne(teamWrapper);
						if (team != null) {
							// Step 3: Query team members
							QueryWrapper<MartialTeamMember> memberWrapper = new QueryWrapper<>();
							memberWrapper.eq("team_id", team.getId());
							memberWrapper.eq("is_deleted", 0);
							List<MartialTeamMember> members = teamMemberMapper.selectList(memberWrapper);
							// Step 4: Get member athlete info
							for (MartialTeamMember member : members) {
								Map<String, Object> memberData = new HashMap<>();
								memberData.put("id", member.getId());
								MartialAthlete athlete = athleteMapper.selectById(member.getAthleteId());
								memberData.put("name", athlete != null ? athlete.getPlayerName() : "");
								memberData.put("gender", athlete != null ? athlete.getGender() : "");
								memberList.add(memberData);
							}
						}
					}
					dto.setMembers(memberList);
				}
				
				participantDTOs.add(dto);
			}
			groupDTO.setParticipants(participantDTOs);
			groupDTO.setStatus(calculateGroupStatus(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;
	}

	/**
	 * 没有编排数据时，从项目和选手表生成初始分组
	 */
	private ScheduleResultDTO generateInitialScheduleResult(Long competitionId) {
		ScheduleResultDTO result = new ScheduleResultDTO();
		result.setIsDraft(true);
		result.setIsCompleted(false);

		// 1. 获取该赛事的所有项目
		List<MartialProject> projects = projectService.list(
			new QueryWrapper<MartialProject>()
				.eq("competition_id", competitionId)
				.eq("is_deleted", 0)
				.orderByAsc("id")
		);

		if (projects.isEmpty()) {
			result.setCompetitionGroups(new ArrayList<>());
			return result;
		}

		// 2. 获取该赛事的所有选手
		List<MartialAthlete> athletes = athleteService.list(
			new QueryWrapper<MartialAthlete>()
				.eq("competition_id", competitionId)
				.eq("is_deleted", 0)
		);

		// 按项目ID分组选手
		Map<Long, List<MartialAthlete>> athletesByProject = athletes.stream()
			.collect(Collectors.groupingBy(MartialAthlete::getProjectId));

		// 3. 获取该赛事的第一个场地作为默认场地
		List<MartialVenue> venues = venueService.list(
			new QueryWrapper<MartialVenue>()
				.eq("competition_id", competitionId)
				.eq("is_deleted", 0)
				.orderByAsc("id")
				.last("LIMIT 1")
		);

		Long defaultVenueId = venues.isEmpty() ? null : venues.get(0).getId();
		String defaultVenueName = venues.isEmpty() ? "未分配" : venues.get(0).getVenueName();

		// 4. 为每个项目生成分组（单人项目根据maxParticipants拆分）
		List<CompetitionGroupDTO> groupDTOs = new ArrayList<>();
		int displayOrder = 0;
		long tempIdCounter = 1; // Counter for generating unique negative IDs for sub-groups

		for (MartialProject project : projects) {
			List<MartialAthlete> projectAthletes = athletesByProject.getOrDefault(project.getId(), new ArrayList<>());

			// 跳过没有选手的项目
			if (projectAthletes.isEmpty()) {
				continue;
			}

			// 判断项目类型
			Integer projectType = project.getType();
			String typeStr;
			if (projectType != null) {
				switch (projectType) {
					case 1:
						typeStr = "单人";
						break;
					case 2:
					case 3:
						typeStr = "集体";
						break;
					default:
						typeStr = "其他";
						break;
				}
			} else {
				typeStr = "单人";
			}

			// 单人项目：根据maxParticipants拆分
			if ("单人".equals(typeStr)) {
				Integer maxParticipants = project.getMaxParticipants();
				int athleteCount = projectAthletes.size();
				
				// 如果maxParticipants有效且人数超过限制，需要拆分
				if (maxParticipants != null && maxParticipants > 0 && athleteCount > maxParticipants) {
					int numGroups = (int) Math.ceil((double) athleteCount / maxParticipants);
					log.info("项目 '{}' 有{}人，maxParticipants={}，将拆分成{}组", 
						project.getProjectName(), athleteCount, maxParticipants, numGroups);
					
					for (int i = 0; i < numGroups; i++) {
						int startIdx = i * maxParticipants;
						int endIdx = Math.min(startIdx + maxParticipants, athleteCount);
						List<MartialAthlete> subGroupAthletes = projectAthletes.subList(startIdx, endIdx);
						
						CompetitionGroupDTO groupDTO = new CompetitionGroupDTO();
						// 使用唯一的负数ID
						groupDTO.setId(-project.getId() - tempIdCounter++);
						groupDTO.setProjectId(project.getId());
						
						// 如果只有一组，不加组号后缀
						if (numGroups == 1) {
							groupDTO.setTitle(project.getProjectName() + " 未分组");
						} else {
							groupDTO.setTitle(project.getProjectName() + " 第" + (i + 1) + "组");
						}
						groupDTO.setCode("C" + competitionId + "-P" + String.format("%03d", displayOrder + 1));
						groupDTO.setType(typeStr);
						groupDTO.setCount(subGroupAthletes.size() + "人");
						groupDTO.setVenueId(defaultVenueId);
						groupDTO.setVenueName(defaultVenueName);
						groupDTO.setTimeSlotIndex(0);
						groupDTO.setTimeSlot(null);
						
						// 生成参赛者列表
						List<ParticipantDTO> participantDTOs = new ArrayList<>();
						int sortOrder = 1;
						for (MartialAthlete athlete : subGroupAthletes) {
							ParticipantDTO dto = new ParticipantDTO();
							dto.setId(athlete.getId());
							dto.setPlayerName(athlete.getPlayerName());
							dto.setSchoolUnit(athlete.getOrganization());
							dto.setTeamName(athlete.getTeamName());
							dto.setStatus("未签到");
							dto.setSortOrder(sortOrder++);
							participantDTOs.add(dto);
						}
						
						groupDTO.setParticipants(participantDTOs);
			groupDTO.setStatus(calculateGroupStatus(participantDTOs));
						groupDTOs.add(groupDTO);
						displayOrder++;
					}
				} else {
					// 不需要拆分，生成单个分组
					CompetitionGroupDTO groupDTO = createSingleGroup(project, projectAthletes, typeStr, 
						defaultVenueId, defaultVenueName, competitionId, displayOrder);
					groupDTOs.add(groupDTO);
					displayOrder++;
				}
			} else {
				// 集体项目：不拆分
				CompetitionGroupDTO groupDTO = createSingleGroup(project, projectAthletes, typeStr, 
					defaultVenueId, defaultVenueName, competitionId, displayOrder);
				groupDTOs.add(groupDTO);
				displayOrder++;
			}
		}

		result.setCompetitionGroups(groupDTOs);
		return result;
	}

	/**
	 * 创建单个分组DTO
	 */
	private CompetitionGroupDTO createSingleGroup(MartialProject project, List<MartialAthlete> athletes, 
			String typeStr, Long venueId, String venueName, Long competitionId, int displayOrder) {
		CompetitionGroupDTO groupDTO = new CompetitionGroupDTO();
		groupDTO.setId(-project.getId());
		groupDTO.setProjectId(project.getId());
		groupDTO.setTitle(project.getProjectName() + " 未分组");
		groupDTO.setCode("C" + competitionId + "-P" + String.format("%03d", displayOrder + 1));
		groupDTO.setType(typeStr);
		groupDTO.setCount(athletes.size() + "人");
		groupDTO.setVenueId(venueId);
		groupDTO.setVenueName(venueName);
		groupDTO.setTimeSlotIndex(0);
		groupDTO.setTimeSlot(null);
		
		List<ParticipantDTO> participantDTOs = new ArrayList<>();
		int sortOrder = 1;
		for (MartialAthlete athlete : athletes) {
			ParticipantDTO dto = new ParticipantDTO();
			dto.setId(athlete.getId());
			dto.setPlayerName(athlete.getPlayerName());
			dto.setSchoolUnit(athlete.getOrganization());
			dto.setTeamName(athlete.getTeamName());
			dto.setStatus("未签到");
			dto.setSortOrder(sortOrder++);
			participantDTOs.add(dto);
		}
		
		groupDTO.setParticipants(participantDTOs);
			groupDTO.setStatus(calculateGroupStatus(participantDTOs));
		return groupDTO;
	}

	/**
	 * 保存编排草稿
	 *
	 * @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. 更新或创建编排明细
			Long groupId = groupDTO.getId();
			Long realGroupId = groupId;

			// Handle negative ID (draft data from auto-arrange)
			if (groupId != null && groupId < 0) {
				Long projectId = null;
				if (groupDTO.getCode() != null && groupDTO.getCode().contains("-P")) {
					try {
						String suffix = groupDTO.getCode().substring(groupDTO.getCode().lastIndexOf("-P") + 2);
						projectId = Long.parseLong(suffix);
					} catch (Exception e) {
						log.warn("Failed to parse projectId from code: {}", groupDTO.getCode());
					}
				}

				MartialScheduleGroup existingGroup = null;
				if (projectId != null) {
					existingGroup = scheduleGroupMapper.selectOne(
						new QueryWrapper<MartialScheduleGroup>()
							.eq("competition_id", dto.getCompetitionId())
							.eq("project_id", projectId)
							.eq("is_deleted", 0)
							.last("LIMIT 1")
					);
				}

				// Determine project type from DTO
				Integer projectType = null;
				if ("集体".equals(groupDTO.getType())) {
					projectType = 2;
				} else if ("单人".equals(groupDTO.getType())) {
					projectType = 1;
				}
				
				// Calculate participant/team counts
				int participantCount = groupDTO.getParticipants() != null ? groupDTO.getParticipants().size() : 0;
				
				if (existingGroup != null) {
					realGroupId = existingGroup.getId();
					existingGroup.setGroupName(groupDTO.getTitle());
					existingGroup.setProjectType(projectType);
					existingGroup.setTotalParticipants(participantCount);
					existingGroup.setTotalTeams(participantCount);
					existingGroup.setCategory(groupDTO.getCode());
					scheduleGroupMapper.updateById(existingGroup);
				} else {
					MartialScheduleGroup newGroup = new MartialScheduleGroup();
					newGroup.setCompetitionId(Long.valueOf(dto.getCompetitionId()));
					newGroup.setProjectId(projectId);
					newGroup.setGroupName(groupDTO.getTitle());
					newGroup.setProjectType(projectType);
					newGroup.setTotalParticipants(participantCount);
					newGroup.setTotalTeams(participantCount);
					newGroup.setCategory(groupDTO.getCode());
					scheduleGroupMapper.insert(newGroup);
					realGroupId = newGroup.getId();
				}
			}

			MartialScheduleDetail detail = scheduleDetailMapper.selectOne(
				new QueryWrapper<MartialScheduleDetail>()
					.eq("schedule_group_id", realGroupId)
					.eq("is_deleted", 0)
					.last("LIMIT 1")
			);

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

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

			// 设置时间段(上午/下午)
			if (groupDTO.getTimeSlot() != null && groupDTO.getTimeSlot().contains("上午")) {
				detail.setTimePeriod("morning");
			} else if (groupDTO.getTimeSlot() != null && groupDTO.getTimeSlot().contains("下午")) {
				detail.setTimePeriod("afternoon");
			} else {
				detail.setTimePeriod("morning"); // 默认上午
			}

			// 解析日期
			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) {
					// 日期解析失败，使用当天日期
					detail.setScheduleDate(LocalDate.now());
				}
			}

			// 如果日期仍为空，设置默认日期
			if (detail.getScheduleDate() == null) {
				detail.setScheduleDate(LocalDate.now());
			}

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

			// 1.5 同步更新项目的venue_id，保持数据一致性
			if (groupDTO.getVenueId() != null) {
				MartialScheduleGroup group = scheduleGroupMapper.selectById(realGroupId);
				if (group != null && group.getProjectId() != null) {
					MartialProject project = projectService.getById(group.getProjectId());
					if (project != null) {
						project.setVenueId(groupDTO.getVenueId());
						projectService.updateById(project);
					}
				}
			}

			// 2. 更新参赛者信息
			if (groupDTO.getParticipants() != null) {
				for (ParticipantDTO participantDTO : groupDTO.getParticipants()) {
					// Query by participant_id (registration ID) and schedule_group_id, not by primary key
					MartialScheduleParticipant participant = scheduleParticipantMapper.selectOne(
						new QueryWrapper<MartialScheduleParticipant>()
							.eq("participant_id", participantDTO.getId())
							.eq("schedule_group_id", realGroupId)
							.eq("is_deleted", 0)
							.last("LIMIT 1")
					);
					if (participant != null) {
						participant.setCheckInStatus(participantDTO.getStatus());
						participant.setPerformanceOrder(participantDTO.getSortOrder());
						participant.setScheduleStatus("draft");
						scheduleParticipantMapper.updateById(participant);
					} else {
						// Create new participant record if not exists
						MartialScheduleParticipant newParticipant = new MartialScheduleParticipant();
						newParticipant.setScheduleGroupId(realGroupId);
						newParticipant.setScheduleDetailId(detail.getId()); // Set schedule_detail_id
						newParticipant.setParticipantId(Long.valueOf(participantDTO.getId()));
						newParticipant.setOrganization(participantDTO.getSchoolUnit());
						newParticipant.setCheckInStatus(participantDTO.getStatus());
						newParticipant.setPerformanceOrder(participantDTO.getSortOrder());
						newParticipant.setScheduleStatus("draft");
						scheduleParticipantMapper.insert(newParticipant);
					}
				}
			}
		}

		return true;
	}

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

		if (groups.isEmpty()) {
			// 没有分组数据，视为成功（可能是初始状态，尚未进行自动编排）
			return true;
		}

		// 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)
		);

		// 按分组和出场顺序分配选手编号
		Map<Long, Integer> groupCounters = new HashMap<>();
		participants.sort((a, b) -> {
			int groupCompare = a.getScheduleGroupId().compareTo(b.getScheduleGroupId());
			if (groupCompare != 0) return groupCompare;
			return Integer.compare(a.getPerformanceOrder() != null ? a.getPerformanceOrder() : 0, 
			                       b.getPerformanceOrder() != null ? b.getPerformanceOrder() : 0);
		});
		
		for (MartialScheduleParticipant participant : participants) {
			participant.setScheduleStatus("completed");
			scheduleParticipantMapper.updateById(participant);
			
			// 分配选手编号
			if (participant.getParticipantId() != null) {
				Long groupId = participant.getScheduleGroupId();
				int counter = groupCounters.getOrDefault(groupId, 0) + 1;
				groupCounters.put(groupId, counter);
				
				// 更新选手编号 (格式: 分组序号-出场序号)
				MartialAthlete athlete = athleteMapper.selectById(participant.getParticipantId());
				if (athlete != null && (athlete.getPlayerNo() == null || athlete.getPlayerNo().isEmpty())) {
					athlete.setPlayerNo(String.format("%03d", counter));
					athleteMapper.updateById(athlete);
				}
			}
		}

		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;
	}


	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean updateParticipantCheckInStatus(Long participantId, String status) {
		if (participantId == null || status == null) {
			return false;
		}
		
		MartialScheduleParticipant participant = scheduleParticipantMapper.selectById(participantId);
		if (participant == null) {
			log.warn("参赛者不存在, participantId: {}", participantId);
			return false;
		}
		
		participant.setCheckInStatus(status);
		int result = scheduleParticipantMapper.updateById(participant);
		
		log.info("更新参赛者签到状态: participantId={}, status={}, result={}", participantId, status, result);
		return result > 0;
	}


	/**
	 * Calculate group status based on participants
	 * @return 0-not started, 1-in progress, 2-completed
	 */
	private int calculateGroupStatus(List<ParticipantDTO> participants) {
		if (participants == null || participants.isEmpty()) {
			return 0;
		}
		boolean allCompleted = true;
		boolean anyStarted = false;
		for (ParticipantDTO p : participants) {
			String s = p.getStatus();
			if ("已完成".equals(s) || "已签到".equals(s)) {
				anyStarted = true;
			} else {
				allCompleted = false;
			}
		}
		if (allCompleted && anyStarted) return 2;
		if (anyStarted) return 1;
		return 0;
	}

}
