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

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
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.MartialRegistrationOrder;
import org.springblade.modules.martial.pojo.entity.MartialTeam;
import org.springblade.modules.martial.pojo.entity.MartialTeamMember;
import org.springblade.modules.martial.pojo.vo.MartialRegistrationOrderVO;
import org.springblade.modules.martial.mapper.MartialRegistrationOrderMapper;
import org.springblade.modules.martial.mapper.MartialTeamMemberMapper;
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.IMartialTeamService;
import org.springblade.modules.martial.service.IMartialRegistrationOrderService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * RegistrationOrder 服务实现类
 *
 * @author BladeX
 */
@Service
@AllArgsConstructor
public class MartialRegistrationOrderServiceImpl extends ServiceImpl<MartialRegistrationOrderMapper, MartialRegistrationOrder> implements IMartialRegistrationOrderService {

	private final IMartialCompetitionService competitionService;
	private final IMartialAthleteService athleteService;
	private final IMartialProjectService projectService;
	private final IMartialTeamService teamService;
	private final MartialTeamMemberMapper teamMemberMapper;

	@Override
	public MartialRegistrationOrderVO getDetailWithRelations(Long id) {
		MartialRegistrationOrder order = this.getById(id);
		if (order == null) {
			return null;
		}
		return convertToVO(order);
	}

	/**
	 * Calculate competition status based on time
	 * 1: pending (not started), 2: ongoing, 3: finished
	 */
	private Integer calculateCompetitionStatus(MartialCompetition competition) {
		if (competition == null) {
			return 1;
		}
		java.time.LocalDateTime now = java.time.LocalDateTime.now();
		java.time.LocalDateTime startTime = competition.getCompetitionStartTime();
		java.time.LocalDateTime endTime = competition.getCompetitionEndTime();
		
		if (startTime == null || endTime == null) {
			return 1;
		}
		
		if (now.isBefore(startTime)) {
			return 1; // pending
		} else if (now.isAfter(endTime)) {
			return 3; // finished
		} else {
			return 2; // ongoing
		}
	}

	@Override
	public IPage<MartialRegistrationOrderVO> getListWithRelations(Long userId, Integer status, Integer current, Integer size) {
		// Build query - don't filter by status here, we'll filter after calculating
		LambdaQueryWrapper<MartialRegistrationOrder> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(MartialRegistrationOrder::getUserId, userId);
		queryWrapper.orderByDesc(MartialRegistrationOrder::getCreateTime);

		// Paginate
		IPage<MartialRegistrationOrder> page = new Page<>(current, size);
		IPage<MartialRegistrationOrder> orderPage = this.page(page, queryWrapper);

		// Convert to VO page
		IPage<MartialRegistrationOrderVO> voPage = new Page<>(current, size, orderPage.getTotal());
		
		if (orderPage.getRecords().isEmpty()) {
			voPage.setRecords(new ArrayList<>());
			return voPage;
		}

		// Batch load competition info
		List<Long> competitionIds = orderPage.getRecords().stream()
				.map(MartialRegistrationOrder::getCompetitionId)
				.filter(cid -> cid != null)
				.distinct()
				.collect(Collectors.toList());
		
		Map<Long, MartialCompetition> competitionMap = competitionIds.isEmpty() ? 
				Map.of() : 
				competitionService.listByIds(competitionIds).stream()
						.collect(Collectors.toMap(MartialCompetition::getId, c -> c));

		// Batch load athletes by order IDs
		List<Long> orderIds = orderPage.getRecords().stream()
				.map(MartialRegistrationOrder::getId)
				.collect(Collectors.toList());
		
		LambdaQueryWrapper<MartialAthlete> athleteWrapper = new LambdaQueryWrapper<>();
		athleteWrapper.in(MartialAthlete::getOrderId, orderIds);
		athleteWrapper.eq(MartialAthlete::getIsDeleted, 0);
		List<MartialAthlete> allAthletes = athleteService.list(athleteWrapper);
		
		Map<Long, List<MartialAthlete>> athletesByOrder = allAthletes.stream()
				.collect(Collectors.groupingBy(MartialAthlete::getOrderId));

		// Batch load projects
		List<Long> projectIds = allAthletes.stream()
				.map(MartialAthlete::getProjectId)
				.filter(pid -> pid != null)
				.distinct()
				.collect(Collectors.toList());
		
		Map<Long, MartialProject> projectMap = projectIds.isEmpty() ?
				Map.of() :
				projectService.listByIds(projectIds).stream()
						.collect(Collectors.toMap(MartialProject::getId, p -> p));

		// Batch load teams by team names from athletes
		Set<String> teamNames = allAthletes.stream()
				.map(MartialAthlete::getTeamName)
				.filter(name -> name != null && !name.isEmpty())
				.collect(Collectors.toSet());
		
		Map<String, MartialTeam> teamByName = Map.of();
		Map<Long, List<MartialTeamMember>> membersByTeam = Map.of();
		Map<Long, MartialAthlete> athleteById = Map.of();
		
		if (!teamNames.isEmpty()) {
			LambdaQueryWrapper<MartialTeam> teamWrapper = new LambdaQueryWrapper<>();
			teamWrapper.in(MartialTeam::getTeamName, teamNames);
			teamWrapper.eq(MartialTeam::getIsDeleted, 0);
			List<MartialTeam> teams = teamService.list(teamWrapper);
			teamByName = teams.stream()
					.collect(Collectors.toMap(MartialTeam::getTeamName, t -> t, (a, b) -> a));
			
			// Load team members
			if (!teams.isEmpty()) {
				List<Long> teamIds = teams.stream().map(MartialTeam::getId).collect(Collectors.toList());
				LambdaQueryWrapper<MartialTeamMember> memberWrapper = new LambdaQueryWrapper<>();
				memberWrapper.in(MartialTeamMember::getTeamId, teamIds);
				memberWrapper.eq(MartialTeamMember::getIsDeleted, 0);
				List<MartialTeamMember> allMembers = teamMemberMapper.selectList(memberWrapper);
				membersByTeam = allMembers.stream()
						.collect(Collectors.groupingBy(MartialTeamMember::getTeamId));
				
				// Load member athlete details
				Set<Long> memberAthleteIds = allMembers.stream()
						.map(MartialTeamMember::getAthleteId)
						.collect(Collectors.toSet());
				if (!memberAthleteIds.isEmpty()) {
					List<MartialAthlete> memberAthletes = athleteService.listByIds(memberAthleteIds);
					athleteById = memberAthletes.stream()
							.collect(Collectors.toMap(MartialAthlete::getId, a -> a, (a, b) -> a));
				}
			}
		}
		
		// Make final references for lambda
		final Map<String, MartialTeam> finalTeamByName = teamByName;
		final Map<Long, List<MartialTeamMember>> finalMembersByTeam = membersByTeam;
		final Map<Long, MartialAthlete> finalAthleteById = athleteById;

		// Convert each order to VO
		List<MartialRegistrationOrderVO> voList = orderPage.getRecords().stream()
				.map(order -> {
					MartialRegistrationOrderVO vo = new MartialRegistrationOrderVO();
					BeanUtils.copyProperties(order, vo);

					// Set competition info and calculate dynamic status
					MartialCompetition competition = competitionMap.get(order.getCompetitionId());
					if (competition != null) {
						vo.setCompetitionName(competition.getCompetitionName());
						vo.setLocation(competition.getLocation());
						vo.setStartTime(competition.getCompetitionStartTime() != null ? 
								competition.getCompetitionStartTime().toString() : null);
						vo.setEndTime(competition.getCompetitionEndTime() != null ? 
								competition.getCompetitionEndTime().toString() : null);
						// Calculate status based on competition time
						vo.setStatus(calculateCompetitionStatus(competition));
					} else {
						vo.setStatus(1); // Default to pending
					}

					// Set athlete info
					List<MartialAthlete> athletes = athletesByOrder.getOrDefault(order.getId(), new ArrayList<>());
					if (!athletes.isEmpty()) {
						String athleteNames = athletes.stream()
								.map(MartialAthlete::getPlayerName)
								.distinct()
								.collect(Collectors.joining("、"));
						vo.setAthleteNames(athleteNames);

						List<MartialRegistrationOrderVO.AthleteInfo> athleteList = athletes.stream()
								.collect(Collectors.toMap(
									MartialAthlete::getPlayerName,
									athlete -> {
										MartialRegistrationOrderVO.AthleteInfo info = new MartialRegistrationOrderVO.AthleteInfo();
										info.setId(athlete.getId());
										info.setPlayerName(athlete.getPlayerName());
										info.setGender(athlete.getGender());
										info.setIdCard(athlete.getIdCard());
										
										// Check if this is a team entry
										String teamName = athlete.getTeamName();
										if (teamName != null && !teamName.isEmpty()) {
											MartialTeam team = finalTeamByName.get(teamName);
											if (team != null) {
												info.setIsTeam(true);
												info.setTeamId(team.getId());
												
												// Get team members
												List<MartialTeamMember> members = finalMembersByTeam.getOrDefault(team.getId(), new ArrayList<>());
												List<MartialRegistrationOrderVO.MemberInfo> memberInfoList = members.stream()
														.map(m -> {
															MartialRegistrationOrderVO.MemberInfo mi = new MartialRegistrationOrderVO.MemberInfo();
															MartialAthlete ma = finalAthleteById.get(m.getAthleteId());
															if (ma != null) {
																mi.setId(ma.getId());
																mi.setName(ma.getPlayerName());
																mi.setGender(ma.getGender());
																mi.setIdCard(ma.getIdCard());
															}
															return mi;
														})
														.filter(mi -> mi.getId() != null)
														.collect(Collectors.toList());
												info.setMembers(memberInfoList);
											} else {
												info.setIsTeam(false);
											}
										} else {
											info.setIsTeam(false);
										}
										
										return info;
									},
									(existing, replacement) -> existing
								))
								.values()
								.stream()
								.collect(Collectors.toList());
						vo.setAthleteList(athleteList);

						// Set project info
						List<Long> orderProjectIds = athletes.stream()
								.map(MartialAthlete::getProjectId)
								.filter(pid -> pid != null)
								.distinct()
								.collect(Collectors.toList());

						if (!orderProjectIds.isEmpty()) {
							List<MartialProject> projects = orderProjectIds.stream()
									.map(projectMap::get)
									.filter(p -> p != null)
									.collect(Collectors.toList());

							String projectNames = projects.stream()
									.map(MartialProject::getProjectName)
									.collect(Collectors.joining("、"));
							vo.setProjectNames(projectNames);

							List<MartialRegistrationOrderVO.ProjectInfo> projectList = projects.stream()
									.map(project -> {
										MartialRegistrationOrderVO.ProjectInfo pinfo = new MartialRegistrationOrderVO.ProjectInfo();
										pinfo.setId(project.getId());
										pinfo.setProjectName(project.getProjectName());
										Integer type = project.getType();
										pinfo.setProjectType(type == 1 ? "个人" : "集体");
										return pinfo;
									})
									.collect(Collectors.toList());
							vo.setProjectList(projectList);
						}
					}

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

		// Filter by status if specified
		final Integer filterStatus = status;
		if (filterStatus != null && filterStatus > 0) {
			voList = voList.stream()
					.filter(v -> filterStatus.equals(v.getStatus()))
					.collect(Collectors.toList());
		}
		
		voPage.setRecords(voList);
		voPage.setTotal(voList.size());
		return voPage;
	}

	private MartialRegistrationOrderVO convertToVO(MartialRegistrationOrder order) {
		MartialRegistrationOrderVO vo = new MartialRegistrationOrderVO();
		BeanUtils.copyProperties(order, vo);

		// Get competition info
		if (order.getCompetitionId() != null) {
			MartialCompetition competition = competitionService.getById(order.getCompetitionId());
			if (competition != null) {
				vo.setCompetitionName(competition.getCompetitionName());
				vo.setLocation(competition.getLocation());
				vo.setStartTime(competition.getCompetitionStartTime() != null ? 
						competition.getCompetitionStartTime().toString() : null);
				vo.setEndTime(competition.getCompetitionEndTime() != null ? 
						competition.getCompetitionEndTime().toString() : null);
			}
		}

		// Get athletes for this order
		LambdaQueryWrapper<MartialAthlete> athleteWrapper = new LambdaQueryWrapper<>();
		athleteWrapper.eq(MartialAthlete::getOrderId, order.getId());
		athleteWrapper.eq(MartialAthlete::getIsDeleted, 0);
		List<MartialAthlete> athletes = athleteService.list(athleteWrapper);

		if (!athletes.isEmpty()) {
			String athleteNames = athletes.stream()
					.map(MartialAthlete::getPlayerName)
					.distinct()
					.collect(Collectors.joining("、"));
			vo.setAthleteNames(athleteNames);

			// Load teams for team entries
			Set<String> teamNames = athletes.stream()
					.map(MartialAthlete::getTeamName)
					.filter(name -> name != null && !name.isEmpty())
					.collect(Collectors.toSet());
			
			Map<String, MartialTeam> teamByName = Map.of();
			Map<Long, List<MartialTeamMember>> membersByTeam = Map.of();
			Map<Long, MartialAthlete> athleteById = Map.of();
			
			if (!teamNames.isEmpty()) {
				LambdaQueryWrapper<MartialTeam> teamWrapper = new LambdaQueryWrapper<>();
				teamWrapper.in(MartialTeam::getTeamName, teamNames);
				teamWrapper.eq(MartialTeam::getIsDeleted, 0);
				List<MartialTeam> teams = teamService.list(teamWrapper);
				teamByName = teams.stream()
						.collect(Collectors.toMap(MartialTeam::getTeamName, t -> t, (a, b) -> a));
				
				if (!teams.isEmpty()) {
					List<Long> teamIds = teams.stream().map(MartialTeam::getId).collect(Collectors.toList());
					LambdaQueryWrapper<MartialTeamMember> memberWrapper = new LambdaQueryWrapper<>();
					memberWrapper.in(MartialTeamMember::getTeamId, teamIds);
					memberWrapper.eq(MartialTeamMember::getIsDeleted, 0);
					List<MartialTeamMember> allMembers = teamMemberMapper.selectList(memberWrapper);
					membersByTeam = allMembers.stream()
							.collect(Collectors.groupingBy(MartialTeamMember::getTeamId));
					
					Set<Long> memberAthleteIds = allMembers.stream()
							.map(MartialTeamMember::getAthleteId)
							.collect(Collectors.toSet());
					if (!memberAthleteIds.isEmpty()) {
						List<MartialAthlete> memberAthletes = athleteService.listByIds(memberAthleteIds);
						athleteById = memberAthletes.stream()
								.collect(Collectors.toMap(MartialAthlete::getId, a -> a, (a, b) -> a));
					}
				}
			}
			
			final Map<String, MartialTeam> finalTeamByName = teamByName;
			final Map<Long, List<MartialTeamMember>> finalMembersByTeam = membersByTeam;
			final Map<Long, MartialAthlete> finalAthleteById = athleteById;

			List<MartialRegistrationOrderVO.AthleteInfo> athleteList = athletes.stream()
					.collect(Collectors.toMap(
						MartialAthlete::getPlayerName,
						athlete -> {
							MartialRegistrationOrderVO.AthleteInfo info = new MartialRegistrationOrderVO.AthleteInfo();
							info.setId(athlete.getId());
							info.setPlayerName(athlete.getPlayerName());
							info.setGender(athlete.getGender());
							info.setIdCard(athlete.getIdCard());
							
							String teamName = athlete.getTeamName();
							if (teamName != null && !teamName.isEmpty()) {
								MartialTeam team = finalTeamByName.get(teamName);
								if (team != null) {
									info.setIsTeam(true);
									info.setTeamId(team.getId());
									
									List<MartialTeamMember> members = finalMembersByTeam.getOrDefault(team.getId(), new ArrayList<>());
									List<MartialRegistrationOrderVO.MemberInfo> memberInfoList = members.stream()
											.map(m -> {
												MartialRegistrationOrderVO.MemberInfo mi = new MartialRegistrationOrderVO.MemberInfo();
												MartialAthlete ma = finalAthleteById.get(m.getAthleteId());
												if (ma != null) {
													mi.setId(ma.getId());
													mi.setName(ma.getPlayerName());
													mi.setGender(ma.getGender());
													mi.setIdCard(ma.getIdCard());
												}
												return mi;
											})
											.filter(mi -> mi.getId() != null)
											.collect(Collectors.toList());
									info.setMembers(memberInfoList);
								} else {
									info.setIsTeam(false);
								}
							} else {
								info.setIsTeam(false);
							}
							
							return info;
						},
						(existing, replacement) -> existing
					))
					.values()
					.stream()
					.collect(Collectors.toList());
			vo.setAthleteList(athleteList);

			// Get project info
			List<Long> pids = athletes.stream()
					.map(MartialAthlete::getProjectId)
					.filter(projectId -> projectId != null)
					.distinct()
					.collect(Collectors.toList());

			if (!pids.isEmpty()) {
				List<MartialProject> projects = projectService.listByIds(pids);

				String projectNames = projects.stream()
						.map(MartialProject::getProjectName)
						.collect(Collectors.joining("、"));
				vo.setProjectNames(projectNames);

				List<MartialRegistrationOrderVO.ProjectInfo> projectList = projects.stream()
						.map(project -> {
							MartialRegistrationOrderVO.ProjectInfo pinfo = new MartialRegistrationOrderVO.ProjectInfo();
							pinfo.setId(project.getId());
							pinfo.setProjectName(project.getProjectName());
							Integer type = project.getType();
							pinfo.setProjectType(type == 1 ? "个人" : "集体");
							return pinfo;
						})
						.collect(Collectors.toList());
				vo.setProjectList(projectList);
			}
		}

		return vo;
	}

}
