package com.lesingle.modules.sys.config;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.lesingle.common.constants.RoleConstants;
import com.lesingle.common.constants.TenantConstants;
import com.lesingle.modules.sys.entity.SysPermission;
import com.lesingle.modules.sys.entity.SysRole;
import com.lesingle.modules.sys.entity.SysRolePermission;
import com.lesingle.modules.sys.mapper.SysPermissionMapper;
import com.lesingle.modules.sys.mapper.SysRoleMapper;
import com.lesingle.modules.sys.mapper.SysRolePermissionMapper;
import com.lesingle.modules.sys.mapper.SysTenantMapper;
import com.lesingle.modules.sys.entity.SysTenant;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * 评委角色权限：与 docs/design/menu-config.md「评委端权限码」一致，并从评委租户或 gdlib 模板复制缺失的权限定义。
 */
@Slf4j
@Component
@RequiredArgsConstructor
@Order(100)
public class JudgeRolePermissionConfigurer implements ApplicationRunner {

    /** 与 menu-config 评委端权限码一致 */
    public static final List<String> JUDGE_PERMISSION_CODES = List.of(
            "review:score", "review:read", "review:create", "review:update",
            "activity:read", "judge:read", "judge:assign", "work:read",
            "notice:read", "workbench:read"
    );

    private static final String TEMPLATE_TENANT_CODE_GDLIB = "gdlib";
    private static final String JUDGE_TENANT_CODE = TenantConstants.CODE_JUDGE;

    private final SysPermissionMapper permissionMapper;
    private final SysRolePermissionMapper rolePermissionMapper;
    private final SysRoleMapper roleMapper;
    private final SysTenantMapper tenantMapper;

    @Override
    public void run(ApplicationArguments args) {
        List<SysRole> judgeRoles = roleMapper.selectList(
                new LambdaQueryWrapper<SysRole>()
                        .eq(SysRole::getCode, RoleConstants.JUDGE)
                        .eq(SysRole::getValidState, 1));
        for (SysRole role : judgeRoles) {
            try {
                ensureJudgeRolePermissions(role.getTenantId(), role.getId());
            } catch (Exception e) {
                log.warn("启动时补全评委角色权限失败 tenantId={} roleId={}: {}",
                        role.getTenantId(), role.getId(), e.getMessage());
            }
        }
        if (!judgeRoles.isEmpty()) {
            log.info("评委角色权限补全完成，共 {} 个 judge 角色", judgeRoles.size());
        }
    }

    /**
     * 确保指定租户下评委角色拥有 menu-config 所列权限；缺失的权限从评委租户或 gdlib 复制到本租户后再绑定。
     */
    public void ensureJudgeRolePermissions(Long tenantId, Long roleId) {
        if (tenantId == null || roleId == null) {
            return;
        }
        for (String code : JUDGE_PERMISSION_CODES) {
            SysPermission perm = permissionMapper.selectOne(
                    new LambdaQueryWrapper<SysPermission>()
                            .eq(SysPermission::getTenantId, tenantId)
                            .eq(SysPermission::getCode, code)
                            .eq(SysPermission::getValidState, 1));
            if (perm == null) {
                SysPermission template = findTemplatePermission(code);
                if (template == null) {
                    log.debug("评委权限模板中无编码 {}，跳过", code);
                    continue;
                }
                perm = new SysPermission();
                perm.setTenantId(tenantId);
                perm.setName(template.getName());
                perm.setCode(template.getCode());
                perm.setResource(template.getResource());
                perm.setAction(template.getAction());
                perm.setDescription(template.getDescription());
                permissionMapper.insert(perm);
            }
            Long permId = perm.getId();
            long exists = rolePermissionMapper.selectCount(
                    new LambdaQueryWrapper<SysRolePermission>()
                            .eq(SysRolePermission::getRoleId, roleId)
                            .eq(SysRolePermission::getPermissionId, permId));
            if (exists == 0) {
                SysRolePermission rp = new SysRolePermission();
                rp.setRoleId(roleId);
                rp.setPermissionId(permId);
                rolePermissionMapper.insert(rp);
            }
        }
    }

    private SysPermission findTemplatePermission(String code) {
        Long judgeTid = tenantIdByCode(JUDGE_TENANT_CODE);
        if (judgeTid != null) {
            SysPermission p = permissionMapper.selectOne(
                    new LambdaQueryWrapper<SysPermission>()
                            .eq(SysPermission::getTenantId, judgeTid)
                            .eq(SysPermission::getCode, code)
                            .eq(SysPermission::getValidState, 1));
            if (p != null) {
                return p;
            }
        }
        Long gdlibTid = tenantIdByCode(TEMPLATE_TENANT_CODE_GDLIB);
        if (gdlibTid != null) {
            return permissionMapper.selectOne(
                    new LambdaQueryWrapper<SysPermission>()
                            .eq(SysPermission::getTenantId, gdlibTid)
                            .eq(SysPermission::getCode, code)
                            .eq(SysPermission::getValidState, 1));
        }
        return null;
    }

    private Long tenantIdByCode(String code) {
        SysTenant t = tenantMapper.selectOne(
                new LambdaQueryWrapper<SysTenant>()
                        .eq(SysTenant::getCode, code)
                        .eq(SysTenant::getValidState, 1));
        return t != null ? t.getId() : null;
    }
}
