package org.springblade.modules.martial.service.schedule.query;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.modules.martial.mapper.*;
import org.springblade.modules.martial.pojo.entity.*;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Schedule query service
 * Handles schedule result queries
 * 
 * @author Refactored from MartialScheduleArrangeServiceImpl
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ScheduleQueryService {

    private final MartialScheduleStatusMapper scheduleStatusMapper;
    private final MartialScheduleGroupMapper scheduleGroupMapper;
    private final MartialScheduleDetailMapper scheduleDetailMapper;
    private final MartialScheduleParticipantMapper scheduleParticipantMapper;
    private final MartialAthleteMapper athleteMapper;
    private final MartialTeamMapper teamMapper;
    private final MartialTeamMemberMapper teamMemberMapper;

    /**
     * Get unlocked competition IDs
     */
    public List<Long> getUnlockedCompetitions() {
        LambdaQueryWrapper<MartialScheduleStatus> wrapper = new LambdaQueryWrapper<>();
        wrapper.ne(MartialScheduleStatus::getScheduleStatus, 2)
            .eq(MartialScheduleStatus::getIsDeleted, 0);

        List<MartialScheduleStatus> statusList = scheduleStatusMapper.selectList(wrapper);
        return statusList.stream()
            .map(MartialScheduleStatus::getCompetitionId)
            .collect(Collectors.toList());
    }

    /**
     * Get schedule result for a competition
     */
    public Map<String, Object> getScheduleResult(Long competitionId) {
        MartialScheduleStatus status = getOrCreateScheduleStatus(competitionId);
        List<MartialScheduleGroup> groups = loadScheduleGroups(competitionId);
        List<Map<String, Object>> scheduleGroups = buildScheduleGroupsData(groups);

        Map<String, Object> result = new HashMap<>();
        result.put("scheduleStatus", status.getScheduleStatus());
        result.put("lastAutoScheduleTime", status.getLastAutoScheduleTime());
        result.put("totalGroups", status.getTotalGroups());
        result.put("totalParticipants", status.getTotalParticipants());
        result.put("competitionGroups", scheduleGroups);

        return result;
    }

    public MartialScheduleStatus getOrCreateScheduleStatus(Long competitionId) {
        LambdaQueryWrapper<MartialScheduleStatus> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(MartialScheduleStatus::getCompetitionId, competitionId)
            .eq(MartialScheduleStatus::getIsDeleted, 0)
            .last("LIMIT 1");

        MartialScheduleStatus status = scheduleStatusMapper.selectOne(wrapper);

        if (status == null) {
            status = new MartialScheduleStatus();
            status.setCompetitionId(competitionId);
            status.setScheduleStatus(0);
            status.setTotalGroups(0);
            status.setTotalParticipants(0);
            status.setCreateTime(new Date());
            scheduleStatusMapper.insert(status);
        }

        return status;
    }

    private List<MartialScheduleGroup> loadScheduleGroups(Long competitionId) {
        LambdaQueryWrapper<MartialScheduleGroup> groupWrapper = new LambdaQueryWrapper<>();
        groupWrapper.eq(MartialScheduleGroup::getCompetitionId, competitionId)
            .eq(MartialScheduleGroup::getIsDeleted, 0)
            .orderByAsc(MartialScheduleGroup::getDisplayOrder);
        return scheduleGroupMapper.selectList(groupWrapper);
    }

    private List<Map<String, Object>> buildScheduleGroupsData(List<MartialScheduleGroup> groups) {
        List<Map<String, Object>> scheduleGroups = new ArrayList<>();

        for (MartialScheduleGroup group : groups) {
            Map<String, Object> groupData = buildGroupData(group);
            List<MartialScheduleDetail> details = loadScheduleDetails(group.getId());
            List<Map<String, Object>> scheduleDetails = buildScheduleDetails(details);
            
            groupData.put("scheduleDetails", scheduleDetails);
            if (!details.isEmpty()) {
                MartialScheduleDetail firstDetail = details.get(0);
                groupData.put("venueId", firstDetail.getVenueId());
                groupData.put("venueName", firstDetail.getVenueName());
                groupData.put("timeSlot", firstDetail.getTimeSlot());
                groupData.put("timeSlotIndex", firstDetail.getTimeSlotIndex());
            }

            List<MartialScheduleParticipant> participants = loadParticipants(group.getId());
            
            if (group.getProjectType() == 2) {
                groupData.put("organizationGroups", buildOrganizationGroups(participants, scheduleDetails));
            } else {
                groupData.put("participants", buildIndividualParticipants(participants));
            }

            scheduleGroups.add(groupData);
        }

        return scheduleGroups;
    }

    private Map<String, Object> buildGroupData(MartialScheduleGroup group) {
        Map<String, Object> groupData = new HashMap<>();
        groupData.put("id", group.getId());
        groupData.put("groupName", group.getGroupName());
        groupData.put("projectType", group.getProjectType());
        groupData.put("displayOrder", group.getDisplayOrder());
        groupData.put("totalParticipants", group.getTotalParticipants());
        groupData.put("totalTeams", group.getTotalTeams());
        groupData.put("estimatedDuration", group.getEstimatedDuration());
        groupData.put("projectId", group.getProjectId());
        return groupData;
    }

    private List<MartialScheduleDetail> loadScheduleDetails(Long groupId) {
        LambdaQueryWrapper<MartialScheduleDetail> detailWrapper = new LambdaQueryWrapper<>();
        detailWrapper.eq(MartialScheduleDetail::getScheduleGroupId, groupId)
            .eq(MartialScheduleDetail::getIsDeleted, 0);
        return scheduleDetailMapper.selectList(detailWrapper);
    }

    private List<Map<String, Object>> buildScheduleDetails(List<MartialScheduleDetail> details) {
        List<Map<String, Object>> scheduleDetails = new ArrayList<>();
        for (MartialScheduleDetail detail : details) {
            Map<String, Object> detailData = new HashMap<>();
            detailData.put("venueId", detail.getVenueId());
            detailData.put("venueName", detail.getVenueName());
            detailData.put("scheduleDate", detail.getScheduleDate());
            detailData.put("timeSlot", detail.getTimeSlot());
            detailData.put("timePeriod", detail.getTimePeriod());
            detailData.put("timeSlotIndex", detail.getTimeSlotIndex());
            scheduleDetails.add(detailData);
        }
        return scheduleDetails;
    }

    private List<MartialScheduleParticipant> loadParticipants(Long groupId) {
        LambdaQueryWrapper<MartialScheduleParticipant> participantWrapper = new LambdaQueryWrapper<>();
        participantWrapper.eq(MartialScheduleParticipant::getScheduleGroupId, groupId)
            .eq(MartialScheduleParticipant::getIsDeleted, 0);
        return scheduleParticipantMapper.selectList(participantWrapper);
    }

    private List<Map<String, Object>> buildOrganizationGroups(List<MartialScheduleParticipant> participants,
                                                               List<Map<String, Object>> scheduleDetails) {
        Map<String, List<MartialScheduleParticipant>> orgGroupMap = participants.stream()
            .collect(Collectors.groupingBy(MartialScheduleParticipant::getOrganization));

        List<Map<String, Object>> organizationGroups = new ArrayList<>();
        for (Map.Entry<String, List<MartialScheduleParticipant>> entry : orgGroupMap.entrySet()) {
            Map<String, Object> orgGroup = new HashMap<>();
            orgGroup.put("organization", entry.getKey());
            orgGroup.put("participants", buildTeamParticipants(entry.getValue()));
            orgGroup.put("scheduleDetails", scheduleDetails);
            organizationGroups.add(orgGroup);
        }
        return organizationGroups;
    }

    private List<Map<String, Object>> buildTeamParticipants(List<MartialScheduleParticipant> participants) {
        List<Map<String, Object>> result = new ArrayList<>();
        for (MartialScheduleParticipant p : participants) {
            Map<String, Object> pData = new HashMap<>();
            pData.put("id", p.getParticipantId());
            pData.put("playerName", p.getPlayerName());
            pData.put("schoolUnit", p.getOrganization());
            pData.put("members", loadTeamMembers(p.getPlayerName()));
            result.add(pData);
        }
        return result;
    }

    private List<Map<String, Object>> loadTeamMembers(String teamName) {
        List<Map<String, Object>> memberList = new ArrayList<>();
        LambdaQueryWrapper<MartialTeam> teamWrapper = new LambdaQueryWrapper<>();
        teamWrapper.eq(MartialTeam::getTeamName, teamName)
            .eq(MartialTeam::getIsDeleted, 0)
            .last("LIMIT 1");
        MartialTeam team = teamMapper.selectOne(teamWrapper);

        if (team != null) {
            LambdaQueryWrapper<MartialTeamMember> memberWrapper = new LambdaQueryWrapper<>();
            memberWrapper.eq(MartialTeamMember::getTeamId, team.getId())
                .eq(MartialTeamMember::getIsDeleted, 0);
            List<MartialTeamMember> members = teamMemberMapper.selectList(memberWrapper);

            for (MartialTeamMember member : members) {
                MartialAthlete athlete = athleteMapper.selectById(member.getAthleteId());
                if (athlete != null) {
                    Map<String, Object> memberData = new HashMap<>();
                    memberData.put("id", athlete.getId());
                    memberData.put("playerName", athlete.getPlayerName());
                    memberData.put("organization", athlete.getOrganization());
                    memberList.add(memberData);
                }
            }
        }
        return memberList;
    }

    private List<Map<String, Object>> buildIndividualParticipants(List<MartialScheduleParticipant> participants) {
        List<Map<String, Object>> result = new ArrayList<>();
        for (MartialScheduleParticipant p : participants) {
            Map<String, Object> pData = new HashMap<>();
            pData.put("id", p.getParticipantId());
            pData.put("schoolUnit", p.getOrganization());
            pData.put("playerName", p.getPlayerName());
            pData.put("scheduleDetail", loadParticipantScheduleDetail(p.getScheduleDetailId()));
            result.add(pData);
        }
        return result;
    }

    private Map<String, Object> loadParticipantScheduleDetail(Long detailId) {
        LambdaQueryWrapper<MartialScheduleDetail> pDetailWrapper = new LambdaQueryWrapper<>();
        pDetailWrapper.eq(MartialScheduleDetail::getId, detailId)
            .eq(MartialScheduleDetail::getIsDeleted, 0)
            .last("LIMIT 1");
        MartialScheduleDetail pDetail = scheduleDetailMapper.selectOne(pDetailWrapper);

        if (pDetail != null) {
            Map<String, Object> scheduleDetail = new HashMap<>();
            scheduleDetail.put("venueId", pDetail.getVenueId());
            scheduleDetail.put("venueName", pDetail.getVenueName());
            scheduleDetail.put("scheduleDate", pDetail.getScheduleDate());
            scheduleDetail.put("timeSlot", pDetail.getTimeSlot());
            return scheduleDetail;
        }
        return null;
    }
}
