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

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.martial.pojo.dto.MiniLoginDTO;
import org.springblade.modules.martial.pojo.entity.*;
import org.springblade.modules.martial.pojo.vo.MiniLoginVO;
import org.springblade.modules.martial.service.*;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@Slf4j
@Service
@RequiredArgsConstructor
public class MiniAuthServiceImpl implements IMiniAuthService {

    private final IMartialJudgeInviteService judgeInviteService;
    private final IMartialJudgeService judgeService;
    private final IMartialCompetitionService competitionService;
    private final IMartialVenueService venueService;
    private final IMartialProjectService projectService;
    private final BladeRedis bladeRedis;

    private static final String MINI_LOGIN_CACHE_PREFIX = "mini:login:";
    private static final Duration LOGIN_CACHE_EXPIRE = Duration.ofDays(7);

    @Override
    public R<MiniLoginVO> login(MiniLoginDTO dto) {
        LambdaQueryWrapper<MartialJudgeInvite> inviteQuery = new LambdaQueryWrapper<>();
        inviteQuery.eq(MartialJudgeInvite::getInviteCode, dto.getInviteCode());
        inviteQuery.eq(MartialJudgeInvite::getIsDeleted, 0);
        MartialJudgeInvite invite = judgeInviteService.getOne(inviteQuery);

        if (invite == null) {
            return R.fail("邀请码不存在");
        }

        if (invite.getExpireTime() != null && invite.getExpireTime().isBefore(LocalDateTime.now())) {
            return R.fail("邀请码已过期");
        }

        MartialCompetition competition = competitionService.getById(invite.getCompetitionId());
        if (competition == null) {
            return R.fail("比赛不存在");
        }

        if (!competition.getCompetitionCode().equals(dto.getMatchCode())) {
            return R.fail("比赛编码不匹配");
        }

        MartialJudge judge = judgeService.getById(invite.getJudgeId());
        if (judge == null) {
            return R.fail("评委信息不存在");
        }

        String token = UUID.randomUUID().toString().replace("-", "");
        invite.setAccessToken(token);
        invite.setTokenExpireTime(LocalDateTime.now().plusDays(7));
        invite.setIsUsed(1);
        invite.setUseTime(LocalDateTime.now());
        invite.setLoginIp(dto.getLoginIp());
        invite.setDeviceInfo(dto.getDeviceInfo());
        judgeInviteService.updateById(invite);

        MartialVenue martialVenue = null;
        if (invite.getVenueId() != null) {
            martialVenue = venueService.getById(invite.getVenueId());
        }

        List<MiniLoginVO.ProjectInfo> projects = getProjectsForJudge(invite, competition.getId());

        MiniLoginVO vo = buildLoginVO(token, competition, judge, martialVenue, projects, invite);

        String cacheKey = MINI_LOGIN_CACHE_PREFIX + token;
        bladeRedis.setEx(cacheKey, vo, LOGIN_CACHE_EXPIRE);

        return R.data(vo);
    }

    @Override
    public R<String> logout(String token) {
        String cacheKey = MINI_LOGIN_CACHE_PREFIX + token;
        bladeRedis.del(cacheKey);
        return R.success("登出成功");
    }

    @Override
    public R<Boolean> verifyToken(String token) {
        String cacheKey = MINI_LOGIN_CACHE_PREFIX + token;
        MiniLoginVO vo = bladeRedis.get(cacheKey);
        return R.data(vo != null);
    }

    private List<MiniLoginVO.ProjectInfo> getProjectsForJudge(MartialJudgeInvite invite, Long competitionId) {
        Integer refereeTypeVal = invite.getRefereeType();
        String roleVal = invite.getRole();
        boolean isGeneralJudge = (refereeTypeVal != null && refereeTypeVal == 3) 
            || "general_judge".equals(roleVal) || "general".equals(roleVal);
        
        if (isGeneralJudge) {
            return getAllProjectsByCompetition(competitionId);
        } else if (Func.isNotEmpty(invite.getProjects())) {
            return parseProjects(invite.getProjects());
        } else if (invite.getVenueId() != null) {
            return getProjectsByVenue(invite.getVenueId());
        }
        return new ArrayList<>();
    }

    private MiniLoginVO buildLoginVO(String token, MartialCompetition competition, 
                                      MartialJudge judge, MartialVenue venue, 
                                      List<MiniLoginVO.ProjectInfo> projects,
                                      MartialJudgeInvite invite) {
        MiniLoginVO vo = new MiniLoginVO();
        vo.setToken(token);
        
        String role = invite.getRole();
        Integer refereeType = invite.getRefereeType();
        if ("general_judge".equals(role) || "general".equals(role) || (refereeType != null && refereeType == 3)) {
            vo.setUserRole("general");
        } else if ("chief_judge".equals(role) || (refereeType != null && refereeType == 1)) {
            vo.setUserRole("admin");
        } else {
            vo.setUserRole("pub");
        }
        
        vo.setMatchId(competition.getId());
        vo.setMatchName(competition.getCompetitionName());
        vo.setMatchTime(competition.getCompetitionStartTime() != null ?
            competition.getCompetitionStartTime().toString() : "");
        vo.setJudgeId(judge.getId());
        vo.setJudgeName(judge.getName());
        vo.setVenueId(venue != null ? venue.getId() : null);
        vo.setVenueName(venue != null ? venue.getVenueName() : null);
        vo.setProjects(projects);
        
        return vo;
    }

    private List<MiniLoginVO.ProjectInfo> getAllProjectsByCompetition(Long competitionId) {
        LambdaQueryWrapper<MartialProject> query = new LambdaQueryWrapper<>();
        query.eq(MartialProject::getCompetitionId, competitionId);
        query.eq(MartialProject::getIsDeleted, 0);
        query.orderByAsc(MartialProject::getSortOrder);
        return convertToProjectInfoList(projectService.list(query));
    }

    private List<MiniLoginVO.ProjectInfo> parseProjects(String projectsJson) {
        // TODO: parse JSON if needed in future
        return new ArrayList<>();
    }

    private List<MiniLoginVO.ProjectInfo> getProjectsByVenue(Long venueId) {
        LambdaQueryWrapper<MartialProject> query = new LambdaQueryWrapper<>();
        query.eq(MartialProject::getVenueId, venueId);
        query.eq(MartialProject::getIsDeleted, 0);
        query.orderByAsc(MartialProject::getSortOrder);
        return convertToProjectInfoList(projectService.list(query));
    }

    private List<MiniLoginVO.ProjectInfo> convertToProjectInfoList(List<MartialProject> projects) {
        List<MiniLoginVO.ProjectInfo> result = new ArrayList<>();
        for (MartialProject p : projects) {
            MiniLoginVO.ProjectInfo info = new MiniLoginVO.ProjectInfo();
            info.setProjectId(p.getId());
            info.setProjectName(p.getProjectName());
            result.add(info);
        }
        return result;
    }
}
