package com.lesingle.creation.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lesingle.creation.common.enums.RegistrationStateEnum;
import com.lesingle.creation.dto.work.*;
import com.lesingle.creation.entity.*;
import com.lesingle.creation.common.exception.BusinessException;
import com.lesingle.creation.mapper.*;
import com.lesingle.creation.service.ContestWorkService;
import com.lesingle.creation.vo.work.WorkAttachmentVO;
import com.lesingle.creation.vo.work.WorkStatsVO;
import com.lesingle.creation.vo.work.WorkVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 竞赛作品服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ContestWorkServiceImpl implements ContestWorkService {

    private final ContestWorkMapper workMapper;
    private final ContestWorkAttachmentMapper attachmentMapper;
    private final ContestRegistrationMapper registrationMapper;
    private final ContestMapper contestMapper;
    private final UserMapper userMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public WorkVO submit(SubmitWorkDTO dto, Long tenantId, Long submitterUserId) {
        // 验证报名记录是否存在
        ContestRegistration registration = registrationMapper.selectById(dto.getRegistrationId());
        if (registration == null) {
            throw new BusinessException("报名记录不存在");
        }

        if (!registration.getTenantId().equals(tenantId)) {
            throw new BusinessException("报名记录不属于当前租户");
        }

        // 检查报名状态
        if (!RegistrationStateEnum.PASSED.getCode().equals(registration.getRegistrationState())) {
            throw new BusinessException("报名未通过审核，无法提交作品");
        }

        // 检查提交时间
        Contest contest = contestMapper.selectById(registration.getContestId());
        if (contest == null) {
            throw new BusinessException("活动不存在");
        }

        LocalDateTime now = LocalDateTime.now();
        if (now.isBefore(contest.getSubmitStartTime()) || now.isAfter(contest.getSubmitEndTime())) {
            throw new BusinessException("不在作品提交时间范围内");
        }

        // 检查提交规则
        List<ContestWork> existingWorks = workMapper.selectList(new LambdaQueryWrapper<ContestWork>()
                .eq(ContestWork::getRegistrationId, dto.getRegistrationId())
                .eq(ContestWork::getValidState, 1)
                .orderByDesc(ContestWork::getVersion));

        if ("once".equals(contest.getSubmitRule()) && !existingWorks.isEmpty()) {
            throw new BusinessException("该活动只允许提交一次作品");
        }

        // 如果已有作品，将旧版本标记为非最新
        if (!existingWorks.isEmpty()) {
            LambdaUpdateWrapper<ContestWork> updateWrapper = new LambdaUpdateWrapper<ContestWork>()
                    .set(ContestWork::getIsLatest, false)
                    .eq(ContestWork::getRegistrationId, dto.getRegistrationId())
                    .eq(ContestWork::getValidState, 1);
            workMapper.update(null, updateWrapper);
        }

        // 生成作品编号
        String workNo = generateWorkNo(registration.getContestId(), tenantId);

        // 获取提交人信息
        User submitter = userMapper.selectById(submitterUserId);
        if (submitter == null) {
            throw new BusinessException("提交人不存在");
        }

        // 创建新版本作品
        ContestWork work = new ContestWork();
        work.setTenantId(tenantId);
        work.setContestId(registration.getContestId());
        work.setRegistrationId(dto.getRegistrationId());
        work.setWorkNo(workNo);
        work.setTitle(dto.getTitle());
        work.setDescription(dto.getDescription());
        work.setFiles(dto.getFiles());
        work.setVersion(existingWorks.isEmpty() ? 1 : existingWorks.get(0).getVersion() + 1);
        work.setIsLatest(true);
        work.setStatus("submitted");
        work.setSubmitTime(LocalDateTime.now());
        work.setSubmitterUserId(submitterUserId);
        work.setSubmitterAccountNo(submitter.getUsername());
        work.setSubmitSource("student");
        work.setPreviewUrl(dto.getPreviewUrl());
        work.setPreviewUrls(dto.getPreviewUrls());
        work.setAiModelMeta(dto.getAiModelMeta());
        work.setValidState(1);
        work.setCreateBy(submitterUserId.toString());

        workMapper.insert(work);

        // 创建附件记录
        if (dto.getAttachments() != null && !dto.getAttachments().isEmpty()) {
            for (SubmitWorkDTO.AttachmentDTO attachment : dto.getAttachments()) {
                ContestWorkAttachment workAttachment = new ContestWorkAttachment();
                workAttachment.setTenantId(tenantId);
                workAttachment.setContestId(registration.getContestId());
                workAttachment.setWorkId(work.getId());
                workAttachment.setFileName(attachment.getFileName());
                workAttachment.setFileUrl(attachment.getFileUrl());
                workAttachment.setFileType(attachment.getFileType());
                workAttachment.setSize(attachment.getSize());
                workAttachment.setCreateBy(submitterUserId.toString());
                attachmentMapper.insert(workAttachment);
            }
        }

        log.info("提交作品成功，ID={}, 报名 ID={}", work.getId(), dto.getRegistrationId());

        return convertToVO(work);
    }

    @Override
    public WorkStatsVO getStats(Long contestId) {
        LambdaQueryWrapper<ContestWork> baseWrapper = new LambdaQueryWrapper<ContestWork>()
                .eq(ContestWork::getValidState, 1)
                .eq(ContestWork::getIsLatest, true);
        if (contestId != null) {
            baseWrapper.eq(ContestWork::getContestId, contestId);
        }

        long total = workMapper.selectCount(baseWrapper);
        long submitted = workMapper.selectCount(new LambdaQueryWrapper<ContestWork>()
                .eq(ContestWork::getStatus, "submitted")
                .eq(ContestWork::getValidState, 1)
                .eq(ContestWork::getIsLatest, true)
                .eq(contestId != null, ContestWork::getContestId, contestId));
        long reviewing = workMapper.selectCount(new LambdaQueryWrapper<ContestWork>()
                .eq(ContestWork::getStatus, "reviewing")
                .eq(ContestWork::getValidState, 1)
                .eq(ContestWork::getIsLatest, true)
                .eq(contestId != null, ContestWork::getContestId, contestId));
        long returned = workMapper.selectCount(new LambdaQueryWrapper<ContestWork>()
                .eq(ContestWork::getStatus, "returned")
                .eq(ContestWork::getValidState, 1)
                .eq(ContestWork::getIsLatest, true)
                .eq(contestId != null, ContestWork::getContestId, contestId));

        WorkStatsVO vo = new WorkStatsVO();
        vo.setTotal((int) total);
        vo.setSubmitted((int) submitted);
        vo.setReviewing((int) reviewing);
        vo.setReturned((int) returned);
        return vo;
    }

    @Override
    public Page<WorkVO> pageQuery(WorkQueryDTO queryDTO, Long tenantId) {
        Page<ContestWork> page = new Page<>(queryDTO.getPageNum(), queryDTO.getPageSize());

        LambdaQueryWrapper<ContestWork> wrapper = new LambdaQueryWrapper<ContestWork>()
                .eq(ContestWork::getTenantId, tenantId)
                .eq(ContestWork::getValidState, 1)
                .eq(queryDTO.getLatestOnly(), ContestWork::getIsLatest, true)
                .eq(queryDTO.getContestId() != null, ContestWork::getContestId, queryDTO.getContestId())
                .eq(queryDTO.getRegistrationId() != null, ContestWork::getRegistrationId, queryDTO.getRegistrationId())
                .like(queryDTO.getTitleKeyword() != null, ContestWork::getTitle, queryDTO.getTitleKeyword())
                .eq(queryDTO.getSubmitterId() != null, ContestWork::getSubmitterUserId, queryDTO.getSubmitterId())
                .orderByDesc(ContestWork::getSubmitTime);

        Page<ContestWork> resultPage = workMapper.page(page, wrapper);

        List<WorkVO> voList = resultPage.getRecords().stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());

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

    @Override
    public WorkVO getDetail(Long id, Long tenantId) {
        ContestWork work = workMapper.selectById(id);
        if (work == null || !work.getTenantId().equals(tenantId)) {
            throw new BusinessException("作品不存在");
        }
        return convertToVO(work);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public WorkVO returnWork(Long id, Long tenantId, String reason) {
        ContestWork work = workMapper.selectById(id);
        if (work == null || !work.getTenantId().equals(tenantId)) {
            throw new BusinessException("作品不存在");
        }

        work.setStatus("returned");
        // 这里可以将 reason 存储到某个字段，或者添加到 aiModelMeta 等 JSON 字段中
        work.setAiModelMeta(reason); // 简化处理

        workMapper.updateById(work);
        log.info("退回作品成功，ID={}, 原因={}", id, reason);

        return convertToVO(work);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id, Long tenantId) {
        ContestWork work = workMapper.selectById(id);
        if (work == null || !work.getTenantId().equals(tenantId)) {
            throw new BusinessException("作品不存在");
        }

        work.setValidState(2);
        workMapper.updateById(work);

        // 删除附件
        attachmentMapper.delete(new LambdaQueryWrapper<ContestWorkAttachment>()
                .eq(ContestWorkAttachment::getWorkId, id)
                .eq(ContestWorkAttachment::getDeleted, 0));

        log.info("删除作品成功，ID={}", id);
    }

    @Override
    public List<WorkVO> listByRegistration(Long registrationId, Long tenantId) {
        List<ContestWork> works = workMapper.selectList(new LambdaQueryWrapper<ContestWork>()
                .eq(ContestWork::getTenantId, tenantId)
                .eq(ContestWork::getRegistrationId, registrationId)
                .eq(ContestWork::getValidState, 1)
                .eq(ContestWork::getIsLatest, true)
                .orderByDesc(ContestWork::getSubmitTime));

        return works.stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
    }

    @Override
    public List<WorkVO> getVersionsByRegistration(Long registrationId, Long tenantId) {
        log.info("查询报名的所有作品版本，报名 ID: {}", registrationId);

        // 查询该报名下的所有作品版本（包括历史版本）
        List<ContestWork> works = workMapper.selectList(new LambdaQueryWrapper<ContestWork>()
                .eq(ContestWork::getTenantId, tenantId)
                .eq(ContestWork::getRegistrationId, registrationId)
                .eq(ContestWork::getValidState, 1)
                .orderByDesc(ContestWork::getVersion));

        return works.stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
    }

    @Override
    public Page<WorkVO> getGuidedWorks(WorkQueryDTO queryDTO, Long userId, Long tenantId) {
        log.info("查询教师指导的作品列表，教师 ID: {}", userId);

        // 查询教师指导的报名记录 ID 列表
        // 注：这里假设报名表中有一个指导老师的字段，或者有一个单独的报名表 - 老师关联表
        // 简化处理：假设通过某种方式可以获取到教师指导的报名 ID 列表
        // 实际需要查询 ContestRegistrationTeacher 关联表

        // 查询该教师指导的所有报名记录
        List<ContestRegistration> registrations = registrationMapper.selectList(
                new LambdaQueryWrapper<ContestRegistration>()
                        .eq(ContestRegistration::getValidState, 1)
                        .like(ContestRegistration::getTeacherIds, userId != null ? userId.toString() : "")
        );

        List<Long> registrationIds = registrations.stream()
                .map(ContestRegistration::getId)
                .collect(Collectors.toList());

        if (registrationIds.isEmpty()) {
            return new Page<>(queryDTO.getPageNum(), queryDTO.getPageSize());
        }

        // 分页查询作品
        Page<ContestWork> page = new Page<>(queryDTO.getPageNum(), queryDTO.getPageSize());

        LambdaQueryWrapper<ContestWork> wrapper = new LambdaQueryWrapper<ContestWork>()
                .eq(ContestWork::getTenantId, tenantId)
                .eq(ContestWork::getValidState, 1)
                .eq(queryDTO.getLatestOnly(), ContestWork::getIsLatest, true)
                .in(ContestWork::getRegistrationId, registrationIds)
                .eq(queryDTO.getContestId() != null, ContestWork::getContestId, queryDTO.getContestId())
                .like(queryDTO.getTitleKeyword() != null, ContestWork::getTitle, queryDTO.getTitleKeyword())
                .orderByDesc(ContestWork::getSubmitTime);

        Page<ContestWork> resultPage = workMapper.page(page, wrapper);

        List<WorkVO> voList = resultPage.getRecords().stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());

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

    // ========== 辅助方法 ==========

    /**
     * 生成作品编号
     */
    private String generateWorkNo(Long contestId, Long tenantId) {
        String prefix = "WORK-" + contestId + "-" + tenantId + "-";
        long count = workMapper.selectCount(new LambdaQueryWrapper<ContestWork>()
                .eq(ContestWork::getContestId, contestId)
                .eq(ContestWork::getTenantId, tenantId));
        return prefix + String.format("%06d", count + 1);
    }

    // ========== 转换方法 ==========

    private WorkVO convertToVO(ContestWork work) {
        WorkVO vo = new WorkVO();
        vo.setId(work.getId());
        vo.setTenantId(work.getTenantId());
        vo.setContestId(work.getContestId());
        vo.setRegistrationId(work.getRegistrationId());
        vo.setWorkNo(work.getWorkNo());
        vo.setTitle(work.getTitle());
        vo.setDescription(work.getDescription());
        vo.setFiles(work.getFiles());
        vo.setVersion(work.getVersion());
        vo.setIsLatest(work.getIsLatest());
        vo.setStatus(work.getStatus());
        vo.setSubmitTime(work.getSubmitTime());
        vo.setSubmitterUserId(work.getSubmitterUserId());
        vo.setSubmitterAccountNo(work.getSubmitterAccountNo());
        vo.setSubmitSource(work.getSubmitSource());
        vo.setPreviewUrl(work.getPreviewUrl());
        vo.setPreviewUrls(work.getPreviewUrls());
        vo.setAiModelMeta(work.getAiModelMeta());
        vo.setValidState(work.getValidState());

        // 获取活动名称
        Contest contest = contestMapper.selectById(work.getContestId());
        if (contest != null) {
            vo.setContestName(contest.getContestName());
        }

        // 获取附件列表
        List<ContestWorkAttachment> attachments = attachmentMapper.selectList(
                new LambdaQueryWrapper<ContestWorkAttachment>()
                        .eq(ContestWorkAttachment::getWorkId, work.getId())
                        .eq(ContestWorkAttachment::getDeleted, 0));
        List<WorkAttachmentVO> attachmentVOs = attachments.stream()
                .map(this::convertToAttachmentVO)
                .collect(Collectors.toList());
        vo.setAttachments(attachmentVOs);

        // 获取参赛者信息
        ContestRegistration registration = registrationMapper.selectById(work.getRegistrationId());
        if (registration != null) {
            vo.setParticipantName(registration.getAccountName());
            vo.setParticipantType("team".equals(registration.getRegistrationType()) ? "team" : "personal");
        }

        return vo;
    }

    private WorkAttachmentVO convertToAttachmentVO(ContestWorkAttachment attachment) {
        WorkAttachmentVO vo = new WorkAttachmentVO();
        vo.setId(attachment.getId());
        vo.setFileName(attachment.getFileName());
        vo.setFileUrl(attachment.getFileUrl());
        vo.setFileType(attachment.getFileType());
        vo.setSize(attachment.getSize());
        return vo;
    }
}
