package com.lesingle.creation.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lesingle.creation.common.exception.BusinessException;
import com.lesingle.creation.dto.contest.*;
import com.lesingle.creation.entity.Contest;
import com.lesingle.creation.entity.ContestAttachment;
import com.lesingle.creation.entity.ContestRegistration;
import com.lesingle.creation.entity.ContestTeamMember;
import com.lesingle.creation.mapper.ContestMapper;
import com.lesingle.creation.mapper.ContestRegistrationMapper;
import com.lesingle.creation.mapper.ContestTeamMemberMapper;
import com.lesingle.creation.service.ContestService;
import com.lesingle.creation.vo.contest.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 竞赛服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ContestServiceImpl extends ServiceImpl<ContestMapper, Contest> implements ContestService {

    private final ContestMapper contestMapper;
    private final ContestRegistrationMapper contestRegistrationMapper;
    private final ContestTeamMemberMapper contestTeamMemberMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ContestDetailVO create(CreateContestDTO dto, Long creatorId) {
        log.info("开始创建竞赛，竞赛名称：{}", dto.getContestName());

        // 检查竞赛名称是否已存在
        Contest existingContest = contestMapper.selectByContestName(dto.getContestName());
        if (existingContest != null) {
            throw new BusinessException("竞赛名称已存在");
        }

        // 验证时间顺序
        validateTimeOrder(dto);

        // 创建竞赛
        Contest contest = new Contest();
        BeanUtils.copyProperties(dto, contest);

        // 处理 JSON 字段
        if (dto.getContestTenants() != null && !dto.getContestTenants().isEmpty()) {
            contest.setContestTenants(listToJson(dto.getContestTenants()));
        }
        if (dto.getTargetCities() != null && !dto.getTargetCities().isEmpty()) {
            contest.setTargetCities(listToJson(dto.getTargetCities()));
        }
        if (dto.getAllowedGrades() != null && !dto.getAllowedGrades().isEmpty()) {
            contest.setAllowedGrades(listToJson(dto.getAllowedGrades()));
        }
        if (dto.getAllowedClasses() != null && !dto.getAllowedClasses().isEmpty()) {
            contest.setAllowedClasses(listToJson(dto.getAllowedClasses()));
        }
        if (dto.getOrganizers() != null) {
            contest.setOrganizers("[\"" + dto.getOrganizers() + "\"]");
        }
        if (dto.getCoOrganizers() != null) {
            contest.setCoOrganizers("[\"" + dto.getCoOrganizers() + "\"]");
        }
        if (dto.getSponsors() != null) {
            contest.setSponsors("[\"" + dto.getSponsors() + "\"]");
        }

        contest.setContestState("unpublished");
        contest.setStatus("ongoing");
        contest.setResultState("unpublished");
        contest.setRequireAudit(dto.getRequireAudit() != null ? dto.getRequireAudit() : true);
        contest.setSubmitRule(dto.getSubmitRule() != null ? dto.getSubmitRule() : "once");
        contest.setCreateBy(String.valueOf(creatorId));

        contestMapper.insert(contest);
        log.info("竞赛创建成功，竞赛 ID: {}", contest.getId());

        return convertToDetailVO(contest);
    }

    @Override
    public Page<ContestListVO> pageList(ContestQueryDTO queryDTO, Long tenantId) {
        log.info("分页查询竞赛列表，页码：{}, 每页大小：{}", queryDTO.getPage(), queryDTO.getPageSize());

        int page = queryDTO.getPage() != null ? queryDTO.getPage() : 1;
        int pageSize = queryDTO.getPageSize() != null ? queryDTO.getPageSize() : 10;

        Page<Contest> contestPage = new Page<>(page, pageSize);
        LambdaQueryWrapper<Contest> wrapper = new LambdaQueryWrapper<>();

        wrapper.eq(Contest::getValidState, 1);

        // 关键字查询
        if (StringUtils.hasText(queryDTO.getContestName())) {
            wrapper.like(Contest::getContestName, queryDTO.getContestName());
        }

        // 状态筛选
        if (StringUtils.hasText(queryDTO.getContestState())) {
            wrapper.eq(Contest::getContestState, queryDTO.getContestState());
        }

        // 类型筛选
        if (StringUtils.hasText(queryDTO.getContestType())) {
            wrapper.eq(Contest::getContestType, queryDTO.getContestType());
        }

        // 进度状态筛选
        if (StringUtils.hasText(queryDTO.getStatus())) {
            wrapper.eq(Contest::getStatus, queryDTO.getStatus());
        }

        // 可见范围筛选
        if (StringUtils.hasText(queryDTO.getVisibility())) {
            wrapper.eq(Contest::getVisibility, queryDTO.getVisibility());
        }

        wrapper.orderByDesc(Contest::getCreateTime);

        Page<Contest> resultPage = contestMapper.selectPage(contestPage, wrapper);

        // 转换为 VO 并计算阶段
        List<ContestListVO> voList = resultPage.getRecords().stream()
                .map(this::convertToListVO)
                .collect(Collectors.toList());

        Page<ContestListVO> voPage = new Page<>(resultPage.getCurrent(), resultPage.getSize(), resultPage.getTotal());
        voPage.setRecords(voList);

        return voPage;
    }

    @Override
    public ContestDetailVO detail(Long id, Long tenantId) {
        log.info("查询竞赛详情，竞赛 ID: {}", id);

        Contest contest = contestMapper.selectById(id);
        if (contest == null) {
            throw new BusinessException("竞赛不存在");
        }

        return convertToDetailVO(contest);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ContestDetailVO update(Long id, UpdateContestDTO dto, Long modifierId) {
        log.info("更新竞赛，竞赛 ID: {}", id);

        Contest existingContest = contestMapper.selectById(id);
        if (existingContest == null) {
            throw new BusinessException("竞赛不存在");
        }

        // 如果更新了竞赛名称，检查是否重复
        if (StringUtils.hasText(dto.getContestName()) &&
            !dto.getContestName().equals(existingContest.getContestName())) {
            Contest conflictContest = contestMapper.selectByContestName(dto.getContestName());
            if (conflictContest != null) {
                throw new BusinessException("竞赛名称已存在");
            }
        }

        // 验证时间顺序
        validateTimeOrder(dto);

        // 更新竞赛信息
        Contest contest = new Contest();
        contest.setId(id);
        BeanUtils.copyProperties(dto, contest, "id");

        // 处理 JSON 字段
        if (dto.getContestTenants() != null) {
            contest.setContestTenants(dto.getContestTenants().isEmpty() ? null : listToJson(dto.getContestTenants()));
        }
        if (dto.getTargetCities() != null) {
            contest.setTargetCities(dto.getTargetCities().isEmpty() ? null : listToJson(dto.getTargetCities()));
        }
        if (dto.getAllowedGrades() != null) {
            contest.setAllowedGrades(dto.getAllowedGrades().isEmpty() ? null : listToJson(dto.getAllowedGrades()));
        }
        if (dto.getAllowedClasses() != null) {
            contest.setAllowedClasses(dto.getAllowedClasses().isEmpty() ? null : listToJson(dto.getAllowedClasses()));
        }
        if (dto.getOrganizers() != null) {
            contest.setOrganizers("[\"" + dto.getOrganizers() + "\"]");
        }
        if (dto.getCoOrganizers() != null) {
            contest.setCoOrganizers("[\"" + dto.getCoOrganizers() + "\"]");
        }
        if (dto.getSponsors() != null) {
            contest.setSponsors("[\"" + dto.getSponsors() + "\"]");
        }

        contest.setUpdateBy(String.valueOf(modifierId));

        contestMapper.updateById(contest);
        log.info("竞赛更新成功，竞赛 ID: {}", id);

        return convertToDetailVO(contestMapper.selectById(id));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ContestDetailVO publish(Long id, String contestState, Long modifierId) {
        log.info("发布/取消发布竞赛，竞赛 ID: {}, 状态：{}", id, contestState);

        Contest contest = contestMapper.selectById(id);
        if (contest == null) {
            throw new BusinessException("竞赛不存在");
        }

        Contest updateContest = new Contest();
        updateContest.setId(id);
        updateContest.setContestState(contestState);
        updateContest.setUpdateBy(String.valueOf(modifierId));

        contestMapper.updateById(updateContest);
        log.info("竞赛发布状态更新成功，竞赛 ID: {}", id);

        return convertToDetailVO(contestMapper.selectById(id));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ContestDetailVO finish(Long id, Long modifierId) {
        log.info("标记竞赛为完结，竞赛 ID: {}", id);

        Contest contest = contestMapper.selectById(id);
        if (contest == null) {
            throw new BusinessException("竞赛不存在");
        }

        if (!"published".equals(contest.getContestState())) {
            throw new BusinessException("只有已发布的竞赛才能标记为完结");
        }

        if ("finished".equals(contest.getStatus())) {
            throw new BusinessException("竞赛已经完结");
        }

        Contest updateContest = new Contest();
        updateContest.setId(id);
        updateContest.setStatus("finished");
        updateContest.setUpdateBy(String.valueOf(modifierId));

        contestMapper.updateById(updateContest);
        log.info("竞赛标记为完结，竞赛 ID: {}", id);

        return convertToDetailVO(contestMapper.selectById(id));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ContestDetailVO reopen(Long id, Long modifierId) {
        log.info("重新开启竞赛，竞赛 ID: {}", id);

        Contest contest = contestMapper.selectById(id);
        if (contest == null) {
            throw new BusinessException("竞赛不存在");
        }

        if (!"finished".equals(contest.getStatus())) {
            throw new BusinessException("只有已完结的竞赛才能重新开启");
        }

        Contest updateContest = new Contest();
        updateContest.setId(id);
        updateContest.setStatus("ongoing");
        updateContest.setUpdateBy(String.valueOf(modifierId));

        contestMapper.updateById(updateContest);
        log.info("竞赛重新开启，竞赛 ID: {}", id);

        return convertToDetailVO(contestMapper.selectById(id));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id) {
        log.info("删除竞赛，竞赛 ID: {}", id);

        Contest contest = contestMapper.selectById(id);
        if (contest == null) {
            throw new BusinessException("竞赛不存在");
        }

        // 逻辑删除竞赛
        contestMapper.deleteById(id);
        log.info("竞赛删除成功，竞赛 ID: {}", id);
    }

    @Override
    public ContestStatsVO getStats() {
        log.info("获取竞赛统计信息");

        ContestStatsVO stats = new ContestStatsVO();

        // 查询所有有效竞赛
        LambdaQueryWrapper<Contest> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Contest::getValidState, 1);
        List<Contest> contests = contestMapper.selectList(wrapper);

        stats.setTotal(contests.size());

        int unpublished = 0, registering = 0, submitting = 0, reviewing = 0, finished = 0;
        LocalDateTime now = LocalDateTime.now();

        for (Contest contest : contests) {
            String stage = getContestStage(contest, now);
            if ("unpublished".equals(stage)) {
                unpublished++;
            } else if ("registering".equals(stage)) {
                registering++;
            } else if ("submitting".equals(stage)) {
                submitting++;
            } else if ("reviewing".equals(stage)) {
                reviewing++;
            } else if ("finished".equals(stage)) {
                finished++;
            }
        }

        stats.setUnpublished(unpublished);
        stats.setRegistering(registering);
        stats.setSubmitting(submitting);
        stats.setReviewing(reviewing);
        stats.setFinished(finished);

        return stats;
    }

    @Override
    public Contest getById(Long id) {
        return contestMapper.selectById(id);
    }

    /**
     * 判断竞赛当前阶段
     */
    private String getContestStage(Contest contest, LocalDateTime now) {
        if ("unpublished".equals(contest.getContestState())) {
            return "unpublished";
        }
        if ("finished".equals(contest.getStatus())) {
            return "finished";
        }

        if (contest.getRegisterStartTime() != null && contest.getRegisterEndTime() != null &&
            now.isAfter(contest.getRegisterStartTime()) && now.isBefore(contest.getRegisterEndTime())) {
            return "registering";
        }

        if (contest.getSubmitStartTime() != null && contest.getSubmitEndTime() != null &&
            now.isAfter(contest.getSubmitStartTime()) && now.isBefore(contest.getSubmitEndTime())) {
            return "submitting";
        }

        if (contest.getReviewStartTime() != null && contest.getReviewEndTime() != null &&
            now.isAfter(contest.getReviewStartTime()) && now.isBefore(contest.getReviewEndTime())) {
            return "reviewing";
        }

        if (contest.getReviewEndTime() != null && now.isAfter(contest.getReviewEndTime())) {
            return "finished";
        }

        return "published";
    }

    /**
     * 验证时间顺序
     */
    private void validateTimeOrder(CreateContestDTO dto) {
        if (dto.getRegisterStartTime().isAfter(dto.getRegisterEndTime()) ||
            dto.getRegisterStartTime().isEqual(dto.getRegisterEndTime())) {
            throw new BusinessException("报名开始时间必须早于报名结束时间");
        }

        if (dto.getRegisterEndTime().isAfter(dto.getSubmitStartTime()) ||
            dto.getRegisterEndTime().isEqual(dto.getSubmitStartTime())) {
            throw new BusinessException("报名结束时间必须早于作品提交开始时间");
        }

        if (dto.getSubmitStartTime().isAfter(dto.getSubmitEndTime()) ||
            dto.getSubmitStartTime().isEqual(dto.getSubmitEndTime())) {
            throw new BusinessException("作品提交开始时间必须早于作品提交结束时间");
        }

        if (dto.getSubmitEndTime().isAfter(dto.getReviewStartTime()) ||
            dto.getSubmitEndTime().isEqual(dto.getReviewStartTime())) {
            throw new BusinessException("作品提交结束时间必须早于评审开始时间");
        }

        if (dto.getReviewStartTime().isAfter(dto.getReviewEndTime()) ||
            dto.getReviewStartTime().isEqual(dto.getReviewEndTime())) {
            throw new BusinessException("评审开始时间必须早于评审结束时间");
        }

        if (dto.getStartTime().isAfter(dto.getEndTime()) ||
            dto.getStartTime().isEqual(dto.getEndTime())) {
            throw new BusinessException("竞赛开始时间必须早于竞赛结束时间");
        }
    }

    /**
     * 验证时间顺序（UpdateContestDTO）
     */
    private void validateTimeOrder(UpdateContestDTO dto) {
        // 简化版本，实际需要根据现有数据和更新数据合并验证
    }

    /**
     * List 转 JSON 字符串
     */
    private String listToJson(List<?> list) {
        if (list == null || list.isEmpty()) {
            return null;
        }
        return list.stream()
                .map(item -> item instanceof Integer ? item.toString() : "\"" + item + "\"")
                .collect(Collectors.joining(",", "[", "]"));
    }

    /**
     * 转换为详情 VO
     */
    private ContestDetailVO convertToDetailVO(Contest contest) {
        ContestDetailVO vo = new ContestDetailVO();
        vo.setId(contest.getId());
        vo.setContestName(contest.getContestName());
        vo.setContestType(contest.getContestType());
        vo.setContestState(contest.getContestState());
        vo.setStatus(contest.getStatus());
        vo.setStage(getContestStage(contest, LocalDateTime.now()));
        vo.setStartTime(contest.getStartTime());
        vo.setEndTime(contest.getEndTime());
        vo.setAddress(contest.getAddress());
        vo.setContent(contest.getContent());
        vo.setContestTenants(jsonToList(contest.getContestTenants(), Integer.class));
        vo.setCoverUrl(contest.getCoverUrl());
        vo.setPosterUrl(contest.getPosterUrl());
        vo.setContactName(contest.getContactName());
        vo.setContactPhone(contest.getContactPhone());
        vo.setContactQrcode(contest.getContactQrcode());
        vo.setOrganizers(jsonToList(contest.getOrganizers(), String.class));
        vo.setCoOrganizers(jsonToList(contest.getCoOrganizers(), String.class));
        vo.setSponsors(jsonToList(contest.getSponsors(), String.class));
        vo.setVisibility(contest.getVisibility());
        vo.setTargetCities(jsonToList(contest.getTargetCities(), String.class));
        vo.setAgeMin(contest.getAgeMin());
        vo.setAgeMax(contest.getAgeMax());
        vo.setRegisterStartTime(contest.getRegisterStartTime());
        vo.setRegisterEndTime(contest.getRegisterEndTime());
        vo.setRegisterState(contest.getRegisterState());
        vo.setRequireAudit(contest.getRequireAudit());
        vo.setAllowedGrades(jsonToList(contest.getAllowedGrades(), Integer.class));
        vo.setAllowedClasses(jsonToList(contest.getAllowedClasses(), Integer.class));
        vo.setTeamMinMembers(contest.getTeamMinMembers());
        vo.setTeamMaxMembers(contest.getTeamMaxMembers());
        vo.setSubmitRule(contest.getSubmitRule());
        vo.setSubmitStartTime(contest.getSubmitStartTime());
        vo.setSubmitEndTime(contest.getSubmitEndTime());
        vo.setWorkType(contest.getWorkType());
        vo.setWorkRequirement(contest.getWorkRequirement());
        vo.setReviewRuleId(contest.getReviewRuleId());
        vo.setReviewStartTime(contest.getReviewStartTime());
        vo.setReviewEndTime(contest.getReviewEndTime());
        vo.setResultState(contest.getResultState());
        vo.setResultPublishTime(contest.getResultPublishTime());
        vo.setValidState(contest.getValidState());
        vo.setCreator(Long.parseLong(contest.getCreateBy()));
        vo.setCreateTime(contest.getCreateTime());
        vo.setModifier(Long.parseLong(contest.getUpdateBy()));
        vo.setModifyTime(contest.getUpdateTime());

        // TODO: 统计人数
        vo.setRegistrationCount(0);
        vo.setWorksCount(0);
        vo.setTeamsCount(0);
        vo.setJudgesCount(0);
        vo.setTotalWorksCount(0);
        vo.setReviewedCount(0);

        vo.setAttachments(new ArrayList<>());

        return vo;
    }

    /**
     * 转换为列表 VO
     */
    private ContestListVO convertToListVO(Contest contest) {
        ContestListVO vo = new ContestListVO();
        vo.setId(contest.getId());
        vo.setContestName(contest.getContestName());
        vo.setContestType(contest.getContestType());
        vo.setContestState(contest.getContestState());
        vo.setStatus(contest.getStatus());
        vo.setStage(getContestStage(contest, LocalDateTime.now()));
        vo.setStartTime(contest.getStartTime());
        vo.setEndTime(contest.getEndTime());
        vo.setCoverUrl(contest.getCoverUrl());
        vo.setPosterUrl(contest.getPosterUrl());
        vo.setOrganizers(contest.getOrganizers());
        vo.setVisibility(contest.getVisibility());
        vo.setRegisterStartTime(contest.getRegisterStartTime());
        vo.setRegisterEndTime(contest.getRegisterEndTime());
        vo.setSubmitStartTime(contest.getSubmitStartTime());
        vo.setSubmitEndTime(contest.getSubmitEndTime());
        vo.setReviewStartTime(contest.getReviewStartTime());
        vo.setReviewEndTime(contest.getReviewEndTime());
        vo.setValidState(contest.getValidState());
        vo.setCreateTime(contest.getCreateTime());

        // TODO: 统计人数
        vo.setRegistrationCount(0);
        vo.setWorksCount(0);
        vo.setTeamsCount(0);
        vo.setJudgesCount(0);
        vo.setTotalWorksCount(0);
        vo.setReviewedCount(0);

        vo.setAttachments(new ArrayList<>());

        return vo;
    }

    /**
     * JSON 字符串转 List
     */
    private <T> List<T> jsonToList(String json, Class<T> clazz) {
        if (json == null || json.isEmpty()) {
            return new ArrayList<>();
        }
        // 简化处理，实际需要更完善的 JSON 解析
        List<T> list = new ArrayList<>();
        String content = json.replaceAll("[\\[\\]\"]", "");
        if (content.isEmpty()) {
            return list;
        }
        String[] items = content.split(",");
        for (String item : items) {
            if (clazz == Integer.class) {
                list.add(clazz.cast(Integer.parseInt(item.trim())));
            } else {
                list.add(clazz.cast(item.trim()));
            }
        }
        return list;
    }

    @Override
    public Page<ContestListVO> myContests(ContestQueryDTO queryDTO, Long userId, Long tenantId) {
        log.info("查询我参与的活动列表，用户 ID: {}", userId);

        // 查询用户参与的竞赛 ID 列表（通过报名记录）
        LambdaQueryWrapper<ContestRegistration> registrationWrapper = new LambdaQueryWrapper<>();
        registrationWrapper.eq(ContestRegistration::getUserId, userId);
        
        List<ContestRegistration> registrations = contestRegistrationMapper.selectList(registrationWrapper);
        List<Long> registrationContestIds = registrations.stream()
                .map(ContestRegistration::getContestId)
                .collect(Collectors.toList());

        // 查询用户参与的团队对应的竞赛 ID（通过团队成员身份）
        LambdaQueryWrapper<ContestTeamMember> teamMemberWrapper = new LambdaQueryWrapper<>();
        teamMemberWrapper.eq(ContestTeamMember::getUserId, userId);
        
        List<ContestTeamMember> teamMembers = contestTeamMemberMapper.selectList(teamMemberWrapper);
        List<Long> teamContestIds = teamMembers.stream()
                .map(ContestTeamMember::getTeamId)
                .collect(Collectors.toList());

        // 合并竞赛 ID 列表
        List<Long> contestIds = new ArrayList<>();
        contestIds.addAll(registrationContestIds);
        contestIds.addAll(teamContestIds);
        contestIds = contestIds.stream().distinct().collect(Collectors.toList());

        if (contestIds.isEmpty()) {
            // 如果用户没有参与任何竞赛，返回空列表
            return new Page<>(queryDTO.getPage() != null ? queryDTO.getPage() : 1,
                             queryDTO.getPageSize() != null ? queryDTO.getPageSize() : 10);
        }

        // 分页查询这些竞赛
        int page = queryDTO.getPage() != null ? queryDTO.getPage() : 1;
        int pageSize = queryDTO.getPageSize() != null ? queryDTO.getPageSize() : 10;

        // 在内存中分页
        int start = (page - 1) * pageSize;
        int end = Math.min(start + pageSize, contestIds.size());
        List<Long> pageContestIds = contestIds.subList(start, end);

        // 查询竞赛详情
        LambdaQueryWrapper<Contest> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(Contest::getId, pageContestIds);
        wrapper.eq(Contest::getValidState, 1);
        List<Contest> contests = contestMapper.selectList(wrapper);

        // 转换为 VO
        List<ContestListVO> voList = contests.stream()
                .map(this::convertToListVO)
                .collect(Collectors.toList());

        Page<ContestListVO> voPage = new Page<>(page, pageSize, (long) contestIds.size());
        voPage.setRecords(voList);

        return voPage;
    }
}
