package com.lesingle.modules.sys.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lesingle.common.constants.RoleConstants;
import com.lesingle.common.enums.ErrorCode;
import com.lesingle.common.exception.BusinessException;
import com.lesingle.modules.sys.dto.CreateMenuDto;
import com.lesingle.modules.sys.entity.SysMenu;
import com.lesingle.modules.sys.entity.SysTenantMenu;
import com.lesingle.modules.sys.mapper.SysMenuMapper;
import com.lesingle.modules.sys.mapper.SysTenantMenuMapper;
import com.lesingle.modules.sys.mapper.SysUserMapper;
import com.lesingle.modules.sys.service.ISysMenuService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

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

@Slf4j
@Service
@RequiredArgsConstructor
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements ISysMenuService {

    private final SysTenantMenuMapper tenantMenuMapper;
    private final SysUserMapper userMapper;

    @Override
    public SysMenu createMenu(CreateMenuDto dto) {
        log.info("开始创建菜单，名称：{}", dto.getName());
        SysMenu menu = new SysMenu();
        menu.setName(dto.getName());
        menu.setPath(dto.getPath());
        menu.setIcon(dto.getIcon());
        menu.setComponent(dto.getComponent());
        menu.setParentId(dto.getParentId());
        menu.setPermission(dto.getPermission());
        menu.setSort(dto.getSort() != null ? dto.getSort() : 0);
        save(menu);
        return menu;
    }

    @Override
    public List<SysMenu> findAllTree() {
        List<SysMenu> all = list(new LambdaQueryWrapper<SysMenu>()
                .eq(SysMenu::getValidState, 1)
                .orderByAsc(SysMenu::getSort));
        return buildTree(all, null);
    }

    @Override
    public List<SysMenu> getUserMenus(Long userId, Long tenantId, boolean isSuperAdmin) {
        // 获取所有有效菜单
        List<SysMenu> allMenus = list(new LambdaQueryWrapper<SysMenu>()
                .eq(SysMenu::getValidState, 1)
                .orderByAsc(SysMenu::getSort));

        // 获取租户分配的菜单 ID
        List<SysTenantMenu> tenantMenus = tenantMenuMapper.selectList(
                new LambdaQueryWrapper<SysTenantMenu>().eq(SysTenantMenu::getTenantId, tenantId));
        Set<Long> tenantMenuIds = new HashSet<>(tenantMenus.stream().map(SysTenantMenu::getMenuId).collect(Collectors.toSet()));

        List<String> roles = isSuperAdmin ? Collections.emptyList() : userMapper.selectRolesByUserId(userId);

        // 租户评委与平台评委共用「我的评审」菜单树：机构租户未在 t_sys_tenant_menu 中配置时，按角色合并评委端菜单
        if (!isSuperAdmin && roles != null && roles.contains(RoleConstants.JUDGE)) {
            tenantMenuIds.addAll(collectJudgePortalMenuIds(allMenus));
        }
        // 机构租户纯评委：仅保留「我的评审」菜单树，不包含租户端工作台/数据统计/活动管理等（与 docs/design/menu-config.md 一致）
        if (!isSuperAdmin && shouldHideTenantJudgeManagementMenuForJudge(roles)) {
            tenantMenuIds.clear();
            tenantMenuIds.addAll(collectJudgePortalMenuIds(allMenus));
        }

        if (isSuperAdmin) {
            // 超管：按租户菜单过滤，但不做权限码过滤
            List<SysMenu> filteredMenus = allMenus.stream()
                    .filter(menu -> tenantMenuIds.contains(menu.getId()))
                    .collect(Collectors.toList());

            // 补全父菜单
            Set<Long> filteredIds = filteredMenus.stream().map(SysMenu::getId).collect(Collectors.toSet());
            for (SysMenu menu : new ArrayList<>(filteredMenus)) {
                addParentsIfMissing(menu, allMenus, filteredMenus, filteredIds);
            }

            return buildTree(filteredMenus, null);
        }

        // 获取用户权限
        List<String> userPermissions = userMapper.selectPermissionsByUserId(userId);
        Set<String> permSet = new HashSet<>(userPermissions);

        // 纯评委角色不展示机构端「评委管理」（与 judge:read 权限码重叠，否则侧栏会出现该菜单）
        boolean hideTenantJudgeMgmtForPureJudge = shouldHideTenantJudgeManagementMenuForJudge(roles);

        // 过滤：菜单必须属于租户，且用户有对应权限（无权限要求的菜单直接放行）
        List<SysMenu> filteredMenus = allMenus.stream()
                .filter(menu -> tenantMenuIds.contains(menu.getId()))
                .filter(menu -> menu.getPermission() == null || menu.getPermission().isBlank() || permSet.contains(menu.getPermission()))
                .filter(menu -> !hideTenantJudgeMgmtForPureJudge || !isTenantJudgeManagementMenu(menu))
                .collect(Collectors.toList());

        // 补全父菜单（确保树结构完整）
        Set<Long> filteredIds = filteredMenus.stream().map(SysMenu::getId).collect(Collectors.toSet());
        for (SysMenu menu : new ArrayList<>(filteredMenus)) {
            addParentsIfMissing(menu, allMenus, filteredMenus, filteredIds);
        }

        return buildTree(filteredMenus, null);
    }

    @Override
    public List<SysMenu> getTenantMenus(Long tenantId) {
        if (tenantId == null) return Collections.emptyList();

        // 获取所有有效菜单
        List<SysMenu> allMenus = list(new LambdaQueryWrapper<SysMenu>()
                .eq(SysMenu::getValidState, 1)
                .orderByAsc(SysMenu::getSort));

        // 获取租户已分配的菜单 ID
        List<SysTenantMenu> tenantMenus = tenantMenuMapper.selectList(
                new LambdaQueryWrapper<SysTenantMenu>().eq(SysTenantMenu::getTenantId, tenantId));
        Set<Long> tenantMenuIds = tenantMenus.stream().map(SysTenantMenu::getMenuId).collect(Collectors.toSet());

        // 过滤出租户可用的菜单
        List<SysMenu> filteredMenus = allMenus.stream()
                .filter(menu -> tenantMenuIds.contains(menu.getId()))
                .collect(Collectors.toList());

        // 补全父菜单（确保树结构完整）
        Set<Long> filteredIds = filteredMenus.stream().map(SysMenu::getId).collect(Collectors.toSet());
        for (SysMenu menu : new ArrayList<>(filteredMenus)) {
            addParentsIfMissing(menu, allMenus, filteredMenus, filteredIds);
        }

        return buildTree(filteredMenus, null);
    }

    @Override
    public SysMenu findDetail(Long id) {
        SysMenu menu = getById(id);
        if (menu == null) {
            throw BusinessException.of(ErrorCode.NOT_FOUND, "菜单不存在");
        }
        // 加载子菜单
        List<SysMenu> children = list(new LambdaQueryWrapper<SysMenu>()
                .eq(SysMenu::getParentId, id)
                .eq(SysMenu::getValidState, 1)
                .orderByAsc(SysMenu::getSort));
        menu.setChildren(children);
        return menu;
    }

    @Override
    public SysMenu updateMenu(Long id, CreateMenuDto dto) {
        log.info("开始更新菜单，ID：{}", id);
        SysMenu menu = new SysMenu();
        menu.setId(id);
        if (dto.getName() != null) menu.setName(dto.getName());
        if (dto.getPath() != null) menu.setPath(dto.getPath());
        if (dto.getIcon() != null) menu.setIcon(dto.getIcon());
        if (dto.getComponent() != null) menu.setComponent(dto.getComponent());
        if (dto.getParentId() != null) menu.setParentId(dto.getParentId());
        if (dto.getPermission() != null) menu.setPermission(dto.getPermission());
        if (dto.getSort() != null) menu.setSort(dto.getSort());
        updateById(menu);
        return getById(id);
    }

    @Override
    public void removeMenu(Long id) {
        log.info("删除菜单，ID：{}", id);
        removeById(id);
    }

    /** 构建菜单树 */
    private List<SysMenu> buildTree(List<SysMenu> menus, Long parentId) {
        return menus.stream()
                .filter(m -> Objects.equals(m.getParentId(), parentId))
                .peek(m -> m.setChildren(buildTree(menus, m.getId())))
                .collect(Collectors.toList());
    }

    /** 机构租户「评委管理」页（非评委工作台） */
    private static final String TENANT_JUDGE_MANAGEMENT_COMPONENT = "contests/judges/Index";

    /**
     * 仅评委角色（无 tenant_admin / super_admin）不展示机构端评委管理菜单
     */
    private boolean shouldHideTenantJudgeManagementMenuForJudge(List<String> roles) {
        if (roles == null || roles.isEmpty()) {
            return false;
        }
        if (!roles.contains(RoleConstants.JUDGE)) {
            return false;
        }
        return !roles.contains(RoleConstants.TENANT_ADMIN) && !roles.contains(RoleConstants.SUPER_ADMIN);
    }

    private boolean isTenantJudgeManagementMenu(SysMenu menu) {
        return TENANT_JUDGE_MANAGEMENT_COMPONENT.equals(menu.getComponent());
    }

    /**
     * 评委端菜单：评审任务、预设评语及其父级（与 docs/design/menu-config 一致，不依赖固定菜单 ID）
     */
    private Set<Long> collectJudgePortalMenuIds(List<SysMenu> allMenus) {
        Set<Long> ids = new HashSet<>();
        Set<String> leafComponents = Set.of("activities/Review", "activities/PresetComments");
        for (SysMenu m : allMenus) {
            if (m.getComponent() != null && leafComponents.contains(m.getComponent())) {
                ids.add(m.getId());
                Long pid = m.getParentId();
                while (pid != null) {
                    if (ids.contains(pid)) {
                        break;
                    }
                    ids.add(pid);
                    final Long currentPid = pid;
                    SysMenu parent = allMenus.stream()
                            .filter(x -> x.getId().equals(currentPid))
                            .findFirst()
                            .orElse(null);
                    pid = parent != null ? parent.getParentId() : null;
                }
            }
        }
        return ids;
    }

    /** 递归补全父菜单 */
    private void addParentsIfMissing(SysMenu menu, List<SysMenu> allMenus, List<SysMenu> filtered, Set<Long> filteredIds) {
        if (menu.getParentId() == null || filteredIds.contains(menu.getParentId())) return;
        allMenus.stream()
                .filter(m -> m.getId().equals(menu.getParentId()))
                .findFirst()
                .ifPresent(parent -> {
                    filtered.add(parent);
                    filteredIds.add(parent.getId());
                    addParentsIfMissing(parent, allMenus, filtered, filteredIds);
                });
    }
}
