package com.lesingle.modules.biz.judge.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lesingle.common.constants.RoleConstants;
import com.lesingle.common.constants.TenantConstants;
import com.lesingle.common.enums.CommonStatus;
import com.lesingle.common.enums.ErrorCode;
import com.lesingle.common.enums.UserSource;
import com.lesingle.common.enums.UserType;
import com.lesingle.common.exception.BusinessException;
import com.lesingle.common.result.PageResult;
import com.lesingle.common.util.SecurityUtil;
import com.lesingle.modules.biz.judge.service.IJudgesManagementService;
import com.lesingle.modules.sys.entity.SysRole;
import com.lesingle.modules.sys.entity.SysTenant;
import com.lesingle.modules.sys.entity.SysUser;
import com.lesingle.modules.sys.entity.SysUserRole;
import com.lesingle.modules.sys.mapper.SysRoleMapper;
import com.lesingle.modules.sys.mapper.SysTenantMapper;
import com.lesingle.modules.sys.config.JudgeRolePermissionConfigurer;
import com.lesingle.modules.sys.mapper.SysUserMapper;
import com.lesingle.modules.sys.mapper.SysUserRoleMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

@Slf4j
@Service
@RequiredArgsConstructor
public class JudgesManagementServiceImpl implements IJudgesManagementService {

    private final SysUserMapper sysUserMapper;
    private final SysUserRoleMapper sysUserRoleMapper;
    private final SysRoleMapper sysRoleMapper;
    private final SysTenantMapper sysTenantMapper;
    private final PasswordEncoder passwordEncoder;
    private final JudgeRolePermissionConfigurer judgeRolePermissionConfigurer;

    /**
     * 获取评委专属租户 ID
     */
    private Long getJudgeTenantId() {
        LambdaQueryWrapper<SysTenant> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysTenant::getCode, TenantConstants.CODE_JUDGE);
        SysTenant tenant = sysTenantMapper.selectOne(wrapper);
        if (tenant == null) {
            throw BusinessException.of(ErrorCode.BAD_REQUEST, "评委租户不存在，请先创建 code='judge' 的租户");
        }
        return tenant.getId();
    }

    /**
     * 获取或自动创建评委角色 ID
     */
    private Long getOrCreateJudgeRoleId(Long tenantId) {
        LambdaQueryWrapper<SysRole> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysRole::getCode, RoleConstants.JUDGE);
        wrapper.eq(SysRole::getTenantId, tenantId);
        SysRole role = sysRoleMapper.selectOne(wrapper);
        if (role != null) {
            judgeRolePermissionConfigurer.ensureJudgeRolePermissions(tenantId, role.getId());
            return role.getId();
        }
        // 自动创建 judge 角色
        role = new SysRole();
        role.setTenantId(tenantId);
        role.setCode(RoleConstants.JUDGE);
        role.setName("评委");
        role.setDescription("评委角色");
        sysRoleMapper.insert(role);
        log.info("自动创建评委角色，租户ID：{}，角色ID：{}", tenantId, role.getId());
        judgeRolePermissionConfigurer.ensureJudgeRolePermissions(tenantId, role.getId());
        return role.getId();
    }

    /**
     * 验证评委是否可被当前租户操作（查看/编辑/删除）
     * 返回 true 表示是平台评委（只读），false 表示是本租户评委
     */
    private boolean checkJudgeOwnership(SysUser user) {
        Long currentTenantId = SecurityUtil.getCurrentTenantId();
        Long judgeTenantId = getJudgeTenantId();

        // 不属于当前租户也不属于平台评委租户
        if (!currentTenantId.equals(user.getTenantId()) && !judgeTenantId.equals(user.getTenantId())) {
            throw BusinessException.of(ErrorCode.NOT_FOUND, "评委不存在");
        }
        return judgeTenantId.equals(user.getTenantId());
    }

    /**
     * 验证评委可被修改操作（非平台评委 + 属于当前租户）
     */
    private void checkJudgeWritable(SysUser user) {
        if (checkJudgeOwnership(user)) {
            throw BusinessException.of(ErrorCode.FORBIDDEN, "平台评委不允许修改");
        }
    }

    /** 与前端约定：male / female */
    private static String normalizeJudgeGender(Object raw) {
        if (raw == null) {
            return null;
        }
        String g = raw.toString().trim();
        if (g.isEmpty()) {
            return null;
        }
        if ("male".equals(g) || "female".equals(g)) {
            return g;
        }
        return null;
    }

    /**
     * 将 SysUser 转为前端需要的 Map
     */
    private Map<String, Object> toMap(SysUser user) {
        Long judgeTenantId = getJudgeTenantId();
        Map<String, Object> map = new LinkedHashMap<>();
        map.put("id", user.getId());
        map.put("username", user.getUsername());
        map.put("nickname", user.getNickname());
        map.put("email", user.getEmail());
        map.put("phone", user.getPhone());
        map.put("organization", user.getOrganization());
        map.put("gender", user.getGender());
        map.put("avatar", user.getAvatar());
        map.put("status", user.getStatus());
        map.put("userSource", user.getUserSource());
        map.put("createTime", user.getCreateTime());
        map.put("modifyTime", user.getModifyTime());
        map.put("tenantId", user.getTenantId());
        map.put("isPlatform", judgeTenantId.equals(user.getTenantId()));
        return map;
    }

    @Override
    @Transactional
    public Map<String, Object> createJudge(Map<String, Object> params) {
        String username = (String) params.get("username");
        String password = (String) params.get("password");
        String nickname = (String) params.get("nickname");
        String email = (String) params.get("email");
        String phone = (String) params.get("phone");
        String organization = (String) params.get("organization");
        String gender = normalizeJudgeGender(params.get("gender"));

        if (username == null || username.isBlank()) {
            throw BusinessException.of(ErrorCode.BAD_REQUEST, "用户名不能为空");
        }
        if (password == null || password.isBlank()) {
            throw BusinessException.of(ErrorCode.BAD_REQUEST, "密码不能为空");
        }
        if (gender == null) {
            throw BusinessException.of(ErrorCode.BAD_REQUEST, "请选择性别");
        }

        Long currentTenantId = SecurityUtil.getCurrentTenantId();

        // 检查用户名在当前租户内唯一
        LambdaQueryWrapper<SysUser> dupWrapper = new LambdaQueryWrapper<>();
        dupWrapper.eq(SysUser::getTenantId, currentTenantId);
        dupWrapper.eq(SysUser::getUsername, username);
        if (sysUserMapper.selectCount(dupWrapper) > 0) {
            throw BusinessException.of(ErrorCode.BAD_REQUEST, "该用户名已存在");
        }

        // 创建用户（归属当前租户）
        SysUser user = new SysUser();
        user.setTenantId(currentTenantId);
        user.setUsername(username);
        user.setPassword(passwordEncoder.encode(password));
        user.setNickname(nickname);
        user.setEmail(email);
        user.setPhone(phone);
        user.setOrganization(organization);
        user.setGender(gender);
        user.setUserSource(UserSource.ADMIN_CREATED.getValue());
        user.setUserType(UserType.ADULT.getValue());
        user.setStatus(CommonStatus.ENABLED.getValue());
        sysUserMapper.insert(user);

        // 分配评委角色（在当前租户下查找或自动创建 judge 角色）
        Long judgeRoleId = getOrCreateJudgeRoleId(currentTenantId);
        SysUserRole userRole = new SysUserRole();
        userRole.setUserId(user.getId());
        userRole.setRoleId(judgeRoleId);
        sysUserRoleMapper.insert(userRole);

        log.info("评委账号创建成功，ID：{}，用户名：{}", user.getId(), username);
        return toMap(user);
    }

    @Override
    public PageResult<Map<String, Object>> findAll(Long page, Long pageSize, String keyword, String status) {
        Long currentTenantId = SecurityUtil.getCurrentTenantId();
        Long judgeTenantId = getJudgeTenantId();

        // 查询当前租户和平台评委租户的 judge 角色 ID
        Set<Long> judgeRoleIds = new HashSet<>();
        for (Long tid : List.of(currentTenantId, judgeTenantId)) {
            if (tid == null) continue;
            LambdaQueryWrapper<SysRole> roleWrapper = new LambdaQueryWrapper<>();
            roleWrapper.eq(SysRole::getCode, RoleConstants.JUDGE);
            roleWrapper.eq(SysRole::getTenantId, tid);
            SysRole role = sysRoleMapper.selectOne(roleWrapper);
            if (role != null) {
                judgeRoleIds.add(role.getId());
            }
        }

        // 查询拥有 judge 角色的用户 ID
        Set<Long> judgeUserIds = new HashSet<>();
        if (!judgeRoleIds.isEmpty()) {
            LambdaQueryWrapper<SysUserRole> urWrapper = new LambdaQueryWrapper<>();
            urWrapper.in(SysUserRole::getRoleId, judgeRoleIds);
            List<SysUserRole> userRoles = sysUserRoleMapper.selectList(urWrapper);
            for (SysUserRole ur : userRoles) {
                judgeUserIds.add(ur.getUserId());
            }
        }

        if (judgeUserIds.isEmpty()) {
            return new PageResult<>(Collections.emptyList(), 0L, page, pageSize);
        }

        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        // 只查询拥有 judge 角色且属于当前租户或平台评委租户的用户
        wrapper.in(SysUser::getId, judgeUserIds);
        wrapper.in(SysUser::getTenantId, List.of(currentTenantId, judgeTenantId));

        if (keyword != null && !keyword.isBlank()) {
            wrapper.and(w -> w
                    .like(SysUser::getUsername, keyword)
                    .or().like(SysUser::getNickname, keyword)
                    .or().like(SysUser::getOrganization, keyword));
        }

        if (status != null && !status.isBlank()) {
            wrapper.eq(SysUser::getStatus, status);
        }

        wrapper.orderByDesc(SysUser::getCreateTime);

        Page<SysUser> pageParam = new Page<>(page, pageSize);
        Page<SysUser> result = sysUserMapper.selectPage(pageParam, wrapper);

        List<Map<String, Object>> list = result.getRecords().stream()
                .map(this::toMap)
                .collect(Collectors.toList());

        return new PageResult<>(list, result.getTotal(), result.getCurrent(), result.getSize());
    }

    @Override
    public Map<String, Object> findDetail(Long id) {
        SysUser user = sysUserMapper.selectById(id);
        if (user == null) {
            throw BusinessException.of(ErrorCode.NOT_FOUND, "评委不存在");
        }
        checkJudgeOwnership(user);
        return toMap(user);
    }

    @Override
    @Transactional
    public Map<String, Object> updateJudge(Long id, Map<String, Object> params) {
        SysUser user = sysUserMapper.selectById(id);
        if (user == null) {
            throw BusinessException.of(ErrorCode.NOT_FOUND, "评委不存在");
        }
        checkJudgeWritable(user);

        if (params.containsKey("nickname")) {
            user.setNickname((String) params.get("nickname"));
        }
        if (params.containsKey("email")) {
            user.setEmail((String) params.get("email"));
        }
        if (params.containsKey("phone")) {
            user.setPhone((String) params.get("phone"));
        }
        if (params.containsKey("organization")) {
            user.setOrganization((String) params.get("organization"));
        }
        if (params.containsKey("gender")) {
            user.setGender(normalizeJudgeGender(params.get("gender")));
        }
        if (params.containsKey("password")) {
            String newPassword = (String) params.get("password");
            if (newPassword != null && !newPassword.isBlank()) {
                user.setPassword(passwordEncoder.encode(newPassword));
            }
        }

        sysUserMapper.updateById(user);
        log.info("评委信息更新成功，ID：{}", id);
        return toMap(user);
    }

    @Override
    public void freeze(Long id) {
        updateJudgeStatus(id, CommonStatus.DISABLED.getValue());
        log.info("评委账号已冻结，ID：{}", id);
    }

    @Override
    public void unfreeze(Long id) {
        updateJudgeStatus(id, CommonStatus.ENABLED.getValue());
        log.info("评委账号已解冻，ID：{}", id);
    }

    private void updateJudgeStatus(Long id, String status) {
        SysUser user = sysUserMapper.selectById(id);
        if (user == null) {
            throw BusinessException.of(ErrorCode.NOT_FOUND, "评委不存在");
        }
        checkJudgeWritable(user);

        user.setStatus(status);
        sysUserMapper.updateById(user);
    }

    @Override
    public void remove(Long id) {
        SysUser user = sysUserMapper.selectById(id);
        if (user == null) {
            throw BusinessException.of(ErrorCode.NOT_FOUND, "评委不存在");
        }
        checkJudgeWritable(user);

        sysUserMapper.deleteById(id);
        log.info("评委已删除，ID：{}", id);
    }

    @Override
    @Transactional
    public void batchDelete(List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            return;
        }

        Long currentTenantId = SecurityUtil.getCurrentTenantId();

        // 校验所有 ID 都属于当前租户（不允许删除平台评委）
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(SysUser::getId, ids);
        wrapper.eq(SysUser::getTenantId, currentTenantId);
        Long count = sysUserMapper.selectCount(wrapper);
        if (count != ids.size()) {
            throw BusinessException.of(ErrorCode.BAD_REQUEST, "部分评委不存在或不属于当前机构");
        }

        sysUserMapper.deleteBatchIds(ids);
        log.info("批量删除评委成功，数量：{}", ids.size());
    }
}
