package com.lesingle.modules.biz.contest.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.common.enums.ErrorCode;
import com.lesingle.common.enums.ParticipantType;
import com.lesingle.common.enums.PublishStatus;
import com.lesingle.common.enums.RegistrationStatus;
import com.lesingle.common.exception.BusinessException;
import com.lesingle.common.result.PageResult;
import com.lesingle.modules.biz.contest.dto.CreateRegistrationDto;
import com.lesingle.modules.biz.contest.dto.QueryRegistrationDto;
import com.lesingle.modules.biz.contest.entity.BizContest;
import com.lesingle.modules.biz.contest.entity.BizContestRegistration;
import com.lesingle.modules.biz.contest.entity.BizContestRegistrationTeacher;
import com.lesingle.modules.biz.contest.mapper.ContestMapper;
import com.lesingle.modules.biz.contest.mapper.ContestRegistrationMapper;
import com.lesingle.modules.biz.contest.mapper.ContestRegistrationTeacherMapper;
import com.lesingle.modules.biz.contest.service.IContestRegistrationService;
import com.lesingle.modules.sys.entity.SysTenant;
import com.lesingle.modules.sys.entity.SysUser;
import com.lesingle.modules.sys.mapper.SysTenantMapper;
import com.lesingle.modules.sys.mapper.SysUserMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

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

@Slf4j
@Service
@RequiredArgsConstructor
public class ContestRegistrationServiceImpl extends ServiceImpl<ContestRegistrationMapper, BizContestRegistration>
        implements IContestRegistrationService {

    private final ContestRegistrationMapper contestRegistrationMapper;
    private final ContestRegistrationTeacherMapper contestRegistrationTeacherMapper;
    private final ContestMapper contestMapper;
    private final SysUserMapper sysUserMapper;
    private final SysTenantMapper sysTenantMapper;

    @Override
    public Map<String, Object> createRegistration(CreateRegistrationDto dto, Long tenantId, Long creatorId) {
        log.info("开始创建报名，活动ID：{}，用户ID：{}", dto.getContestId(), dto.getUserId());

        // 验证活动存在且已发布
        BizContest contest = contestMapper.selectById(dto.getContestId());
        if (contest == null) {
            throw BusinessException.of(ErrorCode.NOT_FOUND, "活动不存在");
        }
        if (!PublishStatus.PUBLISHED.getValue().equals(contest.getContestState())) {
            throw BusinessException.of(ErrorCode.BAD_REQUEST, "活动未发布，无法报名");
        }

        // 获取用户信息
        SysUser user = sysUserMapper.selectById(dto.getUserId());
        String accountNo = user != null ? user.getUsername() : null;
        String accountName = user != null ? user.getNickname() : null;

        BizContestRegistration registration = new BizContestRegistration();
        registration.setContestId(dto.getContestId());
        registration.setTenantId(tenantId);
        registration.setRegistrationType(dto.getRegistrationType());
        registration.setTeamId(dto.getTeamId());
        registration.setUserId(dto.getUserId());
        registration.setAccountNo(accountNo);
        registration.setAccountName(accountName);
        registration.setRegistrationState(RegistrationStatus.PENDING.getValue());
        registration.setParticipantType(ParticipantType.SELF.getValue());
        registration.setRegistrationTime(LocalDateTime.now());
        registration.setRegistrant(creatorId != null ? creatorId.intValue() : null);
        registration.setCreator(creatorId != null ? creatorId.intValue() : null);

        save(registration);
        log.info("报名创建成功，ID：{}", registration.getId());

        // 如果创建者是教师角色，自动添加为默认指导教师
        // 简化实现：此处由调用方根据角色判断后调用 addTeacher
        // TODO: 检查创建者角色，自动关联教师

        Map<String, Object> result = registrationToMap(registration);
        return result;
    }

    @Override
    public PageResult<Map<String, Object>> findAll(QueryRegistrationDto dto, Long tenantId, boolean isSuperTenant) {
        log.info("查询报名列表，活动ID：{}，页码：{}", dto.getContestId(), dto.getPage());

        LambdaQueryWrapper<BizContestRegistration> wrapper = new LambdaQueryWrapper<>();

        if (dto.getContestId() != null) {
            wrapper.eq(BizContestRegistration::getContestId, dto.getContestId());
        }
        if (StringUtils.hasText(dto.getRegistrationState())) {
            wrapper.eq(BizContestRegistration::getRegistrationState, dto.getRegistrationState());
        }
        if (StringUtils.hasText(dto.getRegistrationType())) {
            wrapper.eq(BizContestRegistration::getRegistrationType, dto.getRegistrationType());
        }
        if (StringUtils.hasText(dto.getParticipantType())) {
            wrapper.eq(BizContestRegistration::getParticipantType, dto.getParticipantType());
        }
        if (dto.getUserId() != null) {
            wrapper.eq(BizContestRegistration::getUserId, dto.getUserId());
        }
        if (StringUtils.hasText(dto.getKeyword())) {
            wrapper.and(w -> w.like(BizContestRegistration::getAccountNo, dto.getKeyword())
                    .or().like(BizContestRegistration::getAccountName, dto.getKeyword()));
        }

        // 租户过滤
        if (!isSuperTenant && tenantId != null) {
            wrapper.eq(BizContestRegistration::getTenantId, tenantId);
        }

        wrapper.orderByDesc(BizContestRegistration::getRegistrationTime);

        Page<BizContestRegistration> page = new Page<>(dto.getPage(), dto.getPageSize());
        Page<BizContestRegistration> result = contestRegistrationMapper.selectPage(page, wrapper);

        Set<Long> contestIds = result.getRecords().stream()
                .map(BizContestRegistration::getContestId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        Map<Long, BizContest> contestMap = new HashMap<>();
        if (!contestIds.isEmpty()) {
            contestMap = contestMapper.selectBatchIds(contestIds).stream()
                    .collect(Collectors.toMap(BizContest::getId, c -> c));
        }

        Set<Long> organizerTenantIds = new HashSet<>();
        for (BizContest c : contestMap.values()) {
            List<Integer> ct = c.getContestTenants();
            if (ct != null && !ct.isEmpty()) {
                organizerTenantIds.add(ct.get(0).longValue());
            }
        }
        Map<Long, SysTenant> organizerTenantMap = new HashMap<>();
        if (!organizerTenantIds.isEmpty()) {
            for (SysTenant t : sysTenantMapper.selectBatchIds(organizerTenantIds)) {
                if (t != null && t.getId() != null) {
                    organizerTenantMap.put(t.getId(), t);
                }
            }
        }

        List<Map<String, Object>> voList = new ArrayList<>();
        for (BizContestRegistration reg : result.getRecords()) {
            Map<String, Object> map = registrationToMap(reg);
            BizContest contest = contestMap.get(reg.getContestId());
            if (contest != null) {
                Map<String, Object> contestVo = new LinkedHashMap<>();
                contestVo.put("id", contest.getId());
                contestVo.put("contestName", contest.getContestName());
                map.put("contest", contestVo);
                List<Integer> ct = contest.getContestTenants();
                if (ct != null && !ct.isEmpty()) {
                    SysTenant org = organizerTenantMap.get(ct.get(0).longValue());
                    if (org != null) {
                        Map<String, Object> tenantVo = new LinkedHashMap<>();
                        tenantVo.put("id", org.getId());
                        tenantVo.put("name", org.getName());
                        tenantVo.put("code", org.getCode());
                        map.put("creatorTenant", tenantVo);
                    }
                }
            }
            if (reg.getUserId() != null) {
                SysUser user = sysUserMapper.selectById(reg.getUserId());
                if (user != null) {
                    Map<String, Object> userVo = new LinkedHashMap<>();
                    userVo.put("id", user.getId());
                    userVo.put("username", user.getUsername());
                    userVo.put("nickname", user.getNickname());
                    userVo.put("phone", user.getPhone());
                    map.put("user", userVo);
                }
            }
            voList.add(map);
        }

        return PageResult.from(result, voList);
    }

    @Override
    public Map<String, Object> getStats(Long contestId, Long tenantId, boolean isSuperAdmin) {
        log.info("获取报名统计，活动ID：{}，租户ID：{}，超管：{}", contestId, tenantId, isSuperAdmin);

        // 非超管需要按租户过滤
        boolean needTenantFilter = !isSuperAdmin && tenantId != null;

        LambdaQueryWrapper<BizContestRegistration> baseWrapper = new LambdaQueryWrapper<>();
        if (contestId != null) {
            baseWrapper.eq(BizContestRegistration::getContestId, contestId);
        }
        if (needTenantFilter) {
            baseWrapper.eq(BizContestRegistration::getTenantId, tenantId);
        }
        long total = count(baseWrapper);

        LambdaQueryWrapper<BizContestRegistration> pendingWrapper = new LambdaQueryWrapper<>();
        if (contestId != null) {
            pendingWrapper.eq(BizContestRegistration::getContestId, contestId);
        }
        if (needTenantFilter) {
            pendingWrapper.eq(BizContestRegistration::getTenantId, tenantId);
        }
        pendingWrapper.eq(BizContestRegistration::getRegistrationState, RegistrationStatus.PENDING.getValue());
        long pending = count(pendingWrapper);

        LambdaQueryWrapper<BizContestRegistration> passedWrapper = new LambdaQueryWrapper<>();
        if (contestId != null) {
            passedWrapper.eq(BizContestRegistration::getContestId, contestId);
        }
        if (needTenantFilter) {
            passedWrapper.eq(BizContestRegistration::getTenantId, tenantId);
        }
        passedWrapper.eq(BizContestRegistration::getRegistrationState, RegistrationStatus.PASSED.getValue());
        long passed = count(passedWrapper);

        LambdaQueryWrapper<BizContestRegistration> rejectedWrapper = new LambdaQueryWrapper<>();
        if (contestId != null) {
            rejectedWrapper.eq(BizContestRegistration::getContestId, contestId);
        }
        if (needTenantFilter) {
            rejectedWrapper.eq(BizContestRegistration::getTenantId, tenantId);
        }
        rejectedWrapper.eq(BizContestRegistration::getRegistrationState, RegistrationStatus.REJECTED.getValue());
        long rejected = count(rejectedWrapper);

        Map<String, Object> stats = new LinkedHashMap<>();
        stats.put("total", total);
        stats.put("pending", pending);
        stats.put("passed", passed);
        stats.put("rejected", rejected);
        return stats;
    }

    @Override
    public Map<String, Object> findDetail(Long id, Long tenantId) {
        log.info("查询报名详情，ID：{}", id);

        BizContestRegistration registration = getById(id);
        if (registration == null) {
            throw BusinessException.of(ErrorCode.NOT_FOUND, "报名记录不存在");
        }

        Map<String, Object> result = registrationToMap(registration);

        // 活动与主办机构（前端列表/详情需要 contest、creatorTenant）
        if (registration.getContestId() != null) {
            BizContest contest = contestMapper.selectById(registration.getContestId());
            if (contest != null) {
                Map<String, Object> contestVo = new LinkedHashMap<>();
                contestVo.put("id", contest.getId());
                contestVo.put("contestName", contest.getContestName());
                result.put("contest", contestVo);
                List<Integer> ct = contest.getContestTenants();
                if (ct != null && !ct.isEmpty()) {
                    SysTenant org = sysTenantMapper.selectById(ct.get(0).longValue());
                    if (org != null) {
                        Map<String, Object> tenantVo = new LinkedHashMap<>();
                        tenantVo.put("id", org.getId());
                        tenantVo.put("name", org.getName());
                        tenantVo.put("code", org.getCode());
                        result.put("creatorTenant", tenantVo);
                    }
                }
            }
        }

        // 查询用户详情
        if (registration.getUserId() != null) {
            SysUser user = sysUserMapper.selectById(registration.getUserId());
            if (user != null) {
                Map<String, Object> userInfo = new LinkedHashMap<>();
                userInfo.put("id", user.getId());
                userInfo.put("username", user.getUsername());
                userInfo.put("nickname", user.getNickname());
                userInfo.put("phone", user.getPhone());
                userInfo.put("email", user.getEmail());
                userInfo.put("avatar", user.getAvatar());
                result.put("userInfo", userInfo);
                Map<String, Object> userVo = new LinkedHashMap<>();
                userVo.put("id", user.getId());
                userVo.put("username", user.getUsername());
                userVo.put("nickname", user.getNickname());
                userVo.put("phone", user.getPhone());
                result.put("user", userVo);
            }
        }

        // 查询指导教师列表
        LambdaQueryWrapper<BizContestRegistrationTeacher> teacherWrapper = new LambdaQueryWrapper<>();
        teacherWrapper.eq(BizContestRegistrationTeacher::getRegistrationId, id);
        List<BizContestRegistrationTeacher> teachers = contestRegistrationTeacherMapper.selectList(teacherWrapper);
        result.put("teachers", teachers);

        return result;
    }

    @Override
    public Map<String, Object> getMyRegistration(Long contestId, Long userId, Long tenantId) {
        log.info("查询我的报名，活动ID：{}，用户ID：{}", contestId, userId);

        LambdaQueryWrapper<BizContestRegistration> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BizContestRegistration::getContestId, contestId);
        wrapper.eq(BizContestRegistration::getUserId, userId);
        wrapper.last("LIMIT 1");

        BizContestRegistration registration = getOne(wrapper, false);
        if (registration == null) {
            return null;
        }
        return registrationToMap(registration);
    }

    @Override
    public void reviewRegistration(Long id, String state, String reason, Long operatorId, Long tenantId) {
        log.info("审核报名，ID：{}，状态：{}", id, state);

        BizContestRegistration registration = getById(id);
        if (registration == null) {
            throw BusinessException.of(ErrorCode.NOT_FOUND, "报名记录不存在");
        }

        registration.setRegistrationState(state);
        registration.setReason(reason);
        registration.setOperator(operatorId != null ? operatorId.intValue() : null);
        registration.setOperationDate(LocalDateTime.now());
        updateById(registration);

        log.info("报名审核完成，ID：{}，结果：{}", id, state);
    }

    @Override
    public void revokeReview(Long id, Long tenantId) {
        log.info("撤回审核，ID：{}", id);

        BizContestRegistration registration = getById(id);
        if (registration == null) {
            throw BusinessException.of(ErrorCode.NOT_FOUND, "报名记录不存在");
        }

        registration.setRegistrationState(RegistrationStatus.PENDING.getValue());
        registration.setReason(null);
        registration.setOperator(null);
        registration.setOperationDate(null);
        updateById(registration);

        log.info("审核已撤回，ID：{}", id);
    }

    @Override
    public void batchReview(List<Long> ids, String state, String reason, Long operatorId, Long tenantId) {
        log.info("批量审核报名，数量：{}，状态：{}", ids.size(), state);

        for (Long id : ids) {
            reviewRegistration(id, state, reason, operatorId, tenantId);
        }

        log.info("批量审核完成，共处理 {} 条", ids.size());
    }

    @Override
    public void addTeacher(Long registrationId, Long teacherUserId, Long tenantId, Long creatorId) {
        log.info("添加指导教师，报名ID：{}，教师用户ID：{}", registrationId, teacherUserId);

        // 检查重复
        LambdaQueryWrapper<BizContestRegistrationTeacher> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BizContestRegistrationTeacher::getRegistrationId, registrationId);
        wrapper.eq(BizContestRegistrationTeacher::getUserId, teacherUserId);
        Long existCount = contestRegistrationTeacherMapper.selectCount(wrapper);
        if (existCount > 0) {
            throw BusinessException.of(ErrorCode.CONFLICT, "该教师已关联此报名");
        }

        BizContestRegistrationTeacher teacher = new BizContestRegistrationTeacher();
        teacher.setRegistrationId(registrationId);
        teacher.setTenantId(tenantId);
        teacher.setUserId(teacherUserId);
        teacher.setIsDefault(false);
        teacher.setCreator(creatorId != null ? creatorId.intValue() : null);
        teacher.setCreateTime(LocalDateTime.now());
        contestRegistrationTeacherMapper.insert(teacher);

        log.info("指导教师添加成功，报名ID：{}，教师用户ID：{}", registrationId, teacherUserId);
    }

    @Override
    public void removeTeacher(Long registrationId, Long teacherUserId, Long tenantId) {
        log.info("移除指导教师，报名ID：{}，教师用户ID：{}", registrationId, teacherUserId);

        LambdaQueryWrapper<BizContestRegistrationTeacher> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BizContestRegistrationTeacher::getRegistrationId, registrationId);
        wrapper.eq(BizContestRegistrationTeacher::getUserId, teacherUserId);
        contestRegistrationTeacherMapper.delete(wrapper);

        log.info("指导教师移除成功，报名ID：{}，教师用户ID：{}", registrationId, teacherUserId);
    }

    @Override
    public void removeRegistration(Long id, Long tenantId) {
        log.info("删除报名，ID：{}", id);
        removeById(id);
        log.info("报名删除成功，ID：{}", id);
    }

    // ====== 私有辅助方法 ======

    private Map<String, Object> registrationToMap(BizContestRegistration entity) {
        Map<String, Object> map = new LinkedHashMap<>();
        map.put("id", entity.getId());
        map.put("contestId", entity.getContestId());
        map.put("tenantId", entity.getTenantId());
        map.put("registrationType", entity.getRegistrationType());
        map.put("teamId", entity.getTeamId());
        map.put("teamName", entity.getTeamName());
        map.put("userId", entity.getUserId());
        map.put("accountNo", entity.getAccountNo());
        map.put("accountName", entity.getAccountName());
        map.put("role", entity.getRole());
        map.put("registrationState", entity.getRegistrationState());
        map.put("participantType", entity.getParticipantType());
        map.put("childId", entity.getChildId());
        map.put("registrant", entity.getRegistrant());
        map.put("registrationTime", entity.getRegistrationTime());
        map.put("reason", entity.getReason());
        map.put("operator", entity.getOperator());
        map.put("operationDate", entity.getOperationDate());
        map.put("createTime", entity.getCreateTime());
        return map;
    }
}
