package shop.alien.store.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import shop.alien.entity.result.R;
import shop.alien.entity.store.LifeSysMenu;
import shop.alien.entity.store.LifeSysRoleMenu;
import shop.alien.entity.store.vo.MenuWithRoleVo;
import shop.alien.mapper.LifeSysRoleMenuMapper;
import shop.alien.store.service.LifeSysMenuService;
import shop.alien.store.service.LifeSysRoleMenuService;

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

/**
 * 角色菜单关联表 服务实现类
 *
 * @author system
 * @since 2025-01-XX
 */
@Slf4j
@Service
@RequiredArgsConstructor
@Transactional
public class LifeSysRoleMenuServiceImpl extends ServiceImpl<LifeSysRoleMenuMapper, LifeSysRoleMenu> implements LifeSysRoleMenuService {

    private final LifeSysRoleMenuMapper lifeSysRoleMenuMapper;

    private final LifeSysMenuService lifeSysMenuService;

    @Override
    public R<Boolean> assignMenus(Long roleId, List<Long> menuIds) {
        log.info("LifeSysRoleMenuServiceImpl.assignMenus?roleId={}, menuIds={}", roleId, menuIds);

        if (roleId == null) {
            log.error("角色ID不能为空");
            return R.fail("角色ID不能为空");
        }

        if (menuIds == null || menuIds.isEmpty()) {
            log.warn("菜单ID列表为空，将移除角色的所有菜单");
            return removeAllMenus(roleId);
        }

        try {
            // 先移除角色的所有菜单
            LambdaQueryWrapper<LifeSysRoleMenu> deleteWrapper = new LambdaQueryWrapper<>();
            deleteWrapper.eq(LifeSysRoleMenu::getRoleId, roleId);
            lifeSysRoleMenuMapper.delete(deleteWrapper);

            // 批量分配新菜单
            for (Long menuId : menuIds) {
                if (menuId != null) {
                        // 创建新的关联关系
                        LifeSysRoleMenu roleMenu = new LifeSysRoleMenu();
                        roleMenu.setRoleId(roleId);
                        roleMenu.setMenuId(menuId);
                        lifeSysRoleMenuMapper.insert(roleMenu);
                }
            }

            log.info("为角色分配菜单成功，角色ID={}, 菜单数量={}", roleId, menuIds.size());
            return R.success("分配菜单成功");
        } catch (Exception e) {
            log.error("为角色分配菜单失败，角色ID={}", roleId, e);
            return R.fail("分配菜单失败：" + e.getMessage());
        }
    }

    @Override
    public R<Boolean> removeAllMenus(Long roleId) {
        log.info("LifeSysRoleMenuServiceImpl.removeAllMenus?roleId={}", roleId);

        if (roleId == null) {
            log.error("角色ID不能为空");
            return R.fail("角色ID不能为空");
        }

        try {
            LambdaQueryWrapper<LifeSysRoleMenu> deleteWrapper = new LambdaQueryWrapper<>();
            deleteWrapper.eq(LifeSysRoleMenu::getRoleId, roleId);
            int result = lifeSysRoleMenuMapper.delete(deleteWrapper);

            log.info("移除角色的所有菜单成功，角色ID={}, 删除数量={}", roleId, result);
            return R.success("移除菜单成功");
        } catch (Exception e) {
            log.error("移除角色的所有菜单失败，角色ID={}", roleId, e);
            return R.fail("移除菜单失败：" + e.getMessage());
        }
    }

    @Override
    public R<List<Long>> getMenuIdsByRoleId(Long roleId) {
        log.info("LifeSysRoleMenuServiceImpl.getMenuIdsByRoleId?roleId={}", roleId);

        if (roleId == null) {
            log.error("角色ID不能为空");
            return R.fail("角色ID不能为空");
        }

        try {
            LambdaQueryWrapper<LifeSysRoleMenu> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(LifeSysRoleMenu::getRoleId, roleId);
            List<LifeSysRoleMenu> roleMenuList = lifeSysRoleMenuMapper.selectList(queryWrapper);

            List<Long> menuIds = roleMenuList.stream()
                    .map(LifeSysRoleMenu::getMenuId)
                    .filter(menuId -> menuId != null)
                    .collect(Collectors.toList());

            log.info("查询角色菜单成功，角色ID={}, 菜单数量={}", roleId, menuIds.size());
            return R.data(menuIds, "查询成功");
        } catch (Exception e) {
            log.error("查询角色菜单失败，角色ID={}", roleId, e);
            return R.fail("查询菜单失败：" + e.getMessage());
        }
    }

    @Override
    public R<Boolean> addMenu(Long roleId, Long menuId) {
        log.info("LifeSysRoleMenuServiceImpl.addMenu?roleId={}, menuId={}", roleId, menuId);

        if (roleId == null) {
            log.error("角色ID不能为空");
            return R.fail("角色ID不能为空");
        }
        if (menuId == null) {
            log.error("菜单ID不能为空");
            return R.fail("菜单ID不能为空");
        }

        try {
            // 检查是否已存在该关联关系
            LambdaQueryWrapper<LifeSysRoleMenu> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(LifeSysRoleMenu::getRoleId, roleId)
                    .eq(LifeSysRoleMenu::getMenuId, menuId);
            LifeSysRoleMenu existing = lifeSysRoleMenuMapper.selectOne(queryWrapper);
            if (existing != null) {
                log.warn("角色ID={}已拥有菜单ID={}，无需重复添加", roleId, menuId);
                return R.success("菜单已存在，无需重复添加");
            }

            // 创建新的关联关系
            LifeSysRoleMenu roleMenu = new LifeSysRoleMenu();
            roleMenu.setRoleId(roleId);
            roleMenu.setMenuId(menuId);
            int result = lifeSysRoleMenuMapper.insert(roleMenu);

            if (result > 0) {
                log.info("为角色添加菜单成功，角色ID={}, 菜单ID={}", roleId, menuId);
                return R.success("添加菜单成功");
            } else {
                return R.fail("添加菜单失败");
            }
        } catch (Exception e) {
            log.error("为角色添加菜单失败，角色ID={}, 菜单ID={}", roleId, menuId, e);
            return R.fail("添加菜单失败：" + e.getMessage());
        }
    }

    @Override
    public R<Boolean> removeMenu(Long roleId, Long menuId) {
        log.info("LifeSysRoleMenuServiceImpl.removeMenu?roleId={}, menuId={}", roleId, menuId);

        if (roleId == null) {
            log.error("角色ID不能为空");
            return R.fail("角色ID不能为空");
        }
        if (menuId == null) {
            log.error("菜单ID不能为空");
            return R.fail("菜单ID不能为空");
        }

        try {
            LambdaQueryWrapper<LifeSysRoleMenu> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(LifeSysRoleMenu::getRoleId, roleId)
                    .eq(LifeSysRoleMenu::getMenuId, menuId);
            int result = lifeSysRoleMenuMapper.delete(queryWrapper);

            if (result > 0) {
                log.info("移除角色菜单成功，角色ID={}, 菜单ID={}", roleId, menuId);
                return R.success("移除菜单成功");
            } else {
                log.warn("移除角色菜单失败，关联关系不存在，角色ID={}, 菜单ID={}", roleId, menuId);
                return R.fail("关联关系不存在");
            }
        } catch (Exception e) {
            log.error("移除角色菜单失败，角色ID={}, 菜单ID={}", roleId, menuId, e);
            return R.fail("移除菜单失败：" + e.getMessage());
        }
    }

    @Override
    public R<List<Long>> getRoleIdsByMenuId(Long menuId) {
        log.info("LifeSysRoleMenuServiceImpl.getRoleIdsByMenuId?menuId={}", menuId);

        if (menuId == null) {
            log.error("菜单ID不能为空");
            return R.fail("菜单ID不能为空");
        }

        try {
            LambdaQueryWrapper<LifeSysRoleMenu> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(LifeSysRoleMenu::getMenuId, menuId);
            List<LifeSysRoleMenu> roleMenuList = lifeSysRoleMenuMapper.selectList(queryWrapper);

            List<Long> roleIds = roleMenuList.stream()
                    .map(LifeSysRoleMenu::getRoleId)
                    .filter(roleId -> roleId != null)
                    .collect(Collectors.toList());

            log.info("查询菜单关联的角色成功，菜单ID={}, 角色数量={}", menuId, roleIds.size());
            return R.data(roleIds, "查询成功");
        } catch (Exception e) {
            log.error("查询菜单关联的角色失败，菜单ID={}", menuId, e);
            return R.fail("查询角色失败：" + e.getMessage());
        }
    }

    @Override
    public R<List<MenuWithRoleVo>> getMenusWithRoleStatus(Long roleId) {
        log.info("LifeSysRoleMenuServiceImpl.getMenusWithRoleStatus?roleId={}", roleId);

        if (roleId == null) {
            log.error("角色ID不能为空");
            return R.fail("角色ID不能为空");
        }

        try {
            // 1. 查询所有未删除的菜单
            R<List<LifeSysMenu>> menuTreeResult = lifeSysMenuService.getMenuTree(null);
            if (menuTreeResult == null || menuTreeResult.getData() == null || menuTreeResult.getData().isEmpty()) {
                log.warn("未查询到任何菜单");
                return R.data(new ArrayList<>(), "查询成功");
            }
            List<LifeSysMenu> allMenus = menuTreeResult.getData();

            // 2. 查询角色已拥有的菜单ID列表
            LambdaQueryWrapper<LifeSysRoleMenu> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(LifeSysRoleMenu::getRoleId, roleId);
            List<LifeSysRoleMenu> roleMenuList = lifeSysRoleMenuMapper.selectList(queryWrapper);

            Set<Long> ownedMenuIds = roleMenuList.stream()
                    .map(LifeSysRoleMenu::getMenuId)
                    .filter(menuId -> menuId != null)
                    .collect(Collectors.toSet());

            log.info("角色ID={}已拥有的菜单数量={}", roleId, ownedMenuIds.size());

            // 3. 将菜单列表转换为MenuWithRoleVo，并标记是否拥有
            List<MenuWithRoleVo> menuVoList = convertToMenuWithRoleVo(allMenus, ownedMenuIds);

            // 4. 构建树形结构
            List<MenuWithRoleVo> treeList = buildMenuTreeWithRole(menuVoList);

            log.info("查询角色权限成功，角色ID={}, 总菜单数={}, 已拥有数={}", 
                    roleId, allMenus.size(), ownedMenuIds.size());
            return R.data(treeList, "查询成功");
        } catch (Exception e) {
            log.error("查询角色权限失败，角色ID={}", roleId, e);
            return R.fail("查询权限失败：" + e.getMessage());
        }
    }

    /**
     * 将菜单列表转换为MenuWithRoleVo，并标记是否拥有
     *
     * @param menus 菜单列表
     * @param ownedMenuIds 已拥有的菜单ID集合
     * @return MenuWithRoleVo列表
     */
    private List<MenuWithRoleVo> convertToMenuWithRoleVo(List<LifeSysMenu> menus, Set<Long> ownedMenuIds) {
        List<MenuWithRoleVo> voList = new ArrayList<>();
        if (menus == null || menus.isEmpty()) {
            return voList;
        }

        for (LifeSysMenu menu : menus) {
            if (menu == null) {
                continue;
            }
            Boolean hasPermission = ownedMenuIds.contains(menu.getMenuId());
            MenuWithRoleVo vo = MenuWithRoleVo.fromEntity(menu, hasPermission);

            // 递归处理子菜单
            if (menu.getChildren() != null && !menu.getChildren().isEmpty()) {
                List<MenuWithRoleVo> children = convertToMenuWithRoleVo(menu.getChildren(), ownedMenuIds);
                vo.setChildren(children);
            }

            voList.add(vo);
        }

        return voList;
    }

    /**
     * 构建菜单树形结构（带角色权限标记）
     *
     * @param flatList 扁平列表
     * @return 树形结构列表
     */
    private List<MenuWithRoleVo> buildMenuTreeWithRole(List<MenuWithRoleVo> flatList) {
        if (flatList == null || flatList.isEmpty()) {
            return new ArrayList<>();
        }

        // 创建映射：ID到节点的映射，父ID到子节点列表的映射
        Map<Long, MenuWithRoleVo> nodeMap = new HashMap<>();
        Map<Long, List<MenuWithRoleVo>> parentChildMap = new HashMap<>();
        List<MenuWithRoleVo> result = new ArrayList<>();

        // 第一步：建立映射关系
        for (MenuWithRoleVo menu : flatList) {
            Long menuId = menu.getMenuId();
            Long parentId = menu.getParentId() != null ? menu.getParentId() : 0L;

            // 存入节点映射
            nodeMap.put(menuId, menu);

            // 如果是根节点（parentId为0或null），直接添加到结果
            if (parentId == null || parentId == 0) {
                result.add(menu);
            } else {
                // 否则，记录父子关系
                parentChildMap.computeIfAbsent(parentId, k -> new ArrayList<>()).add(menu);
            }
        }

        // 第二步：建立父子关系
        for (MenuWithRoleVo menu : nodeMap.values()) {
            Long menuId = menu.getMenuId();
            if (parentChildMap.containsKey(menuId)) {
                // 对子节点按排序值排序
                List<MenuWithRoleVo> children = parentChildMap.get(menuId);
                children.sort(Comparator.comparing(MenuWithRoleVo::getMenuSort, Comparator.nullsLast(Integer::compareTo)));
                menu.setChildren(children);
            }
        }

        // 对根节点按排序值排序
        result.sort(Comparator.comparing(MenuWithRoleVo::getMenuSort, Comparator.nullsLast(Integer::compareTo)));

        return result;
    }
}

