package com.haha.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.haha.entity.Menu;
import com.haha.entity.RoleMenu;
import com.haha.mapper.MenuMapper;
import com.haha.mapper.RoleMenuMapper;
import com.haha.common.constant.CommonConstants;
import com.haha.service.MenuService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 菜单服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {

    private final RoleMenuMapper roleMenuMapper;

    @Override
    public List<Menu> getAllMenus() {
        return lambdaQuery()
                .eq(Menu::getDeleted, CommonConstants.NOT_DELETED)
                .orderByAsc(Menu::getRank, Menu::getId)
                .list();
    }

    @Override
    public List<Menu> searchByTitle(String title) {
        return lambdaQuery()
                .eq(Menu::getDeleted, CommonConstants.NOT_DELETED)
                .like(Menu::getTitle, title)
                .orderByAsc(Menu::getRank, Menu::getId)
                .list();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Menu createMenu(Menu menu) {
        menu.setCreateTime(LocalDateTime.now());
        menu.setUpdateTime(LocalDateTime.now());
        menu.setDeleted(CommonConstants.NOT_DELETED);
        if (menu.getRank() == null) {
            menu.setRank(99);
        }
        if (menu.getMenuType() == null) {
            menu.setMenuType(0);
        }
        save(menu);
        log.info("创建菜单成功: id={}, title={}", menu.getId(), menu.getTitle());
        return menu;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Menu updateMenu(Menu menu) {
        menu.setUpdateTime(LocalDateTime.now());
        updateById(menu);
        log.info("更新菜单成功: id={}, title={}", menu.getId(), menu.getTitle());
        return menu;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteMenu(Long id) {
        // 递归查找所有子菜单
        List<Long> idsToDelete = new ArrayList<>();
        collectChildIds(id, idsToDelete);
        idsToDelete.add(id);

        // 逻辑删除
        for (Long menuId : idsToDelete) {
            Menu menu = new Menu();
            menu.setId(menuId);
            menu.setDeleted(CommonConstants.DELETED);
            menu.setUpdateTime(LocalDateTime.now());
            updateById(menu);
        }
        log.info("删除菜单成功: id={}, 共删除{}条", id, idsToDelete.size());
    }

    /**
     * 递归收集所有子菜单ID
     */
    private void collectChildIds(Long parentId, List<Long> result) {
        List<Menu> children = lambdaQuery()
                .eq(Menu::getParentId, parentId)
                .eq(Menu::getDeleted, CommonConstants.NOT_DELETED)
                .list();
        for (Menu child : children) {
            result.add(child.getId());
            collectChildIds(child.getId(), result);
        }
    }

    @Override
    public List<Map<String, Object>> getUserMenuTree(List<Long> roleIds) {
        if (roleIds == null || roleIds.isEmpty()) {
            return Collections.emptyList();
        }

        // 查询角色拥有的所有菜单
        List<Menu> menus = baseMapper.selectMenusByRoleIds(roleIds);

        // 过滤只保留菜单和目录类型（0=菜单, 1=iframe, 2=外链），排除按钮(3)
        menus = menus.stream()
                .filter(m -> m.getMenuType() != null && m.getMenuType() != 3)
                .filter(m -> m.getShowLink() == null || m.getShowLink())
                .collect(Collectors.toList());

        // 构建菜单树
        return buildMenuTree(0L, menus);
    }

    /**
     * 递归构建菜单树（前端 asyncRoutes 格式）
     */
    private List<Map<String, Object>> buildMenuTree(Long parentId, List<Menu> allMenus) {
        List<Map<String, Object>> tree = new ArrayList<>();

        List<Menu> children = allMenus.stream()
                .filter(m -> m.getParentId() != null && m.getParentId().equals(parentId))
                .sorted(Comparator.comparing(Menu::getRank, Comparator.nullsLast(Comparator.naturalOrder())))
                .collect(Collectors.toList());

        for (Menu menu : children) {
            Map<String, Object> node = new LinkedHashMap<>();
            node.put("path", menu.getPath());
            node.put("name", menu.getName());

            Map<String, Object> meta = new LinkedHashMap<>();
            if (menu.getIcon() != null && !menu.getIcon().isEmpty()) {
                meta.put("icon", menu.getIcon());
            }
            meta.put("title", menu.getTitle());
            if (menu.getRank() != null) {
                meta.put("rank", menu.getRank());
            }
            if (menu.getShowParent() != null && menu.getShowParent()) {
                meta.put("showParent", true);
            }

            node.put("meta", meta);

            // 递归构建子节点
            List<Map<String, Object>> childNodes = buildMenuTree(menu.getId(), allMenus);
            if (!childNodes.isEmpty()) {
                // 保留完整的树结构，单子节点提升交给前端 SidebarItem 组件处理
                node.put("children", childNodes);
                if (menu.getRedirect() != null && !menu.getRedirect().isEmpty()) {
                    node.put("redirect", menu.getRedirect());
                }
                tree.add(node);
            } else {
                // 叶子节点需要 component
                if (menu.getComponent() != null && !menu.getComponent().isEmpty()) {
                    node.put("component", menu.getComponent());
                }
                tree.add(node);
            }
        }

        return tree;
    }

    @Override
    public List<Long> getMenuIdsByRoleId(Long roleId) {
        return roleMenuMapper.selectList(
                new LambdaQueryWrapper<RoleMenu>()
                        .eq(RoleMenu::getRoleId, roleId)
        ).stream().map(RoleMenu::getMenuId).collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSort(List<Menu> menus) {
        if (menus == null || menus.isEmpty()) {
            return;
        }
        for (Menu menu : menus) {
            if (menu.getId() != null && menu.getRank() != null) {
                baseMapper.updateRank(menu.getId(), menu.getRank());
            }
        }
        log.info("批量更新菜单排序成功: {}条", menus.size());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveRoleMenus(Long roleId, List<Long> menuIds) {
        // 先删除旧关联
        baseMapper.deleteByRoleId(roleId);

        // 再插入新关联
        if (menuIds != null && !menuIds.isEmpty()) {
            for (Long menuId : menuIds) {
                RoleMenu rm = new RoleMenu();
                rm.setRoleId(roleId);
                rm.setMenuId(menuId);
                rm.setCreateTime(LocalDateTime.now());
                roleMenuMapper.insert(rm);
            }
        }
        log.info("保存角色菜单关联成功: roleId={}, menuCount={}", roleId, menuIds != null ? menuIds.size() : 0);
    }
}
