package com.gxwebsoft.common.system.controller;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.hutool.core.stream.CollectorUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.gxwebsoft.common.core.annotation.OperationLog;
import com.gxwebsoft.common.core.utils.JSONUtil;
import com.gxwebsoft.common.core.web.*;
import com.gxwebsoft.common.system.entity.*;
import com.gxwebsoft.common.system.param.MenuImportParam;
import com.gxwebsoft.common.system.param.MenuParam;
import com.gxwebsoft.common.system.param.VersionParam;
import com.gxwebsoft.common.system.service.CompanyService;
import com.gxwebsoft.common.system.service.MenuService;
import com.gxwebsoft.common.system.service.RoleMenuService;
import com.gxwebsoft.common.system.service.RoleService;
import com.gxwebsoft.common.system.service.UserService;
import com.gxwebsoft.common.system.service.VersionService;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 菜单控制器
 *
 * @author WebSoft
 * @since 2018-12-24 16:10:23
 */
@Tag(name = "菜单")
@RestController
@RequestMapping("/api/system/menu")
public class MenuController extends BaseController {
    @Resource
    private MenuService menuService;
    @Resource
    private CompanyService companyService;
    @Resource
    private VersionService versionService;
    @Resource
    private UserService userService;
    @Resource
    private RoleService roleService;
    @Resource
    private RoleMenuService roleMenuService;

    @PreAuthorize("hasAuthority('sys:menu:list')")
    @Operation(summary = "分页查询菜单")
    @GetMapping("/page")
    public ApiResult<PageResult<Menu>> page(MenuParam param) {
        PageParam<Menu, MenuParam> page = new PageParam<>(param);
        page.setDefaultOrder("sort_number asc, create_time desc");
        return success(menuService.page(page, page.getWrapper()));
    }

    @PreAuthorize("hasAuthority('sys:menu:list')")
    @Operation(summary = "查询全部菜单")
    @GetMapping()
    public ApiResult<List<Menu>> list(MenuParam param) {
        PageParam<Menu, MenuParam> page = new PageParam<>(param);
        page.setDefaultOrder("sort_number asc, create_time desc");
        return success(menuService.list(page.getOrderWrapper()));
    }

    @PreAuthorize("hasAuthority('sys:menu:list')")
    @Operation(summary = "根据id查询菜单")
    @GetMapping("/{id}")
    public ApiResult<Menu> get(@PathVariable("id") Integer id) {
        return success(menuService.getById(id));
    }

    @PreAuthorize("hasAuthority('sys:menu:save')")
    @OperationLog
    @Operation(summary = "添加菜单")
    @PostMapping()
    public ApiResult<?> add(@RequestBody Menu menu) {
        if (menu.getParentId() == null) {
            menu.setParentId(0);
        }
        // 去除字符串前面的空格
        menu.setTitle(StrUtil.trimStart(menu.getTitle()));
        menu.setPath(StrUtil.trimStart(menu.getPath()));
        menu.setComponent(StrUtil.trimStart(menu.getComponent()));
        menu.setAuthority(StrUtil.trimStart(menu.getAuthority()));
        if (menuService.save(menu)) {
            return success("添加成功");
        }
        return fail("添加失败");
    }

    @PreAuthorize("hasAuthority('sys:menu:update')")
    @OperationLog
    @Operation(summary = "修改菜单")
    @PutMapping()
    public ApiResult<?> update(@RequestBody Menu menu) {
        // 去除字符串前面的空格
        menu.setTitle(StrUtil.trimStart(menu.getTitle()));
        menu.setPath(StrUtil.trimStart(menu.getPath()));
        menu.setComponent(StrUtil.trimStart(menu.getComponent()));
        menu.setAuthority(StrUtil.trimStart(menu.getAuthority()));
        if (menuService.updateById(menu)) {
            return success("修改成功");
        }
        return fail("修改失败");
    }

    @PreAuthorize("hasAuthority('sys:menu:remove')")
    @OperationLog
    @Operation(summary = "删除菜单")
    @DeleteMapping("/{id}")
    public ApiResult<?> remove(@PathVariable("id") Integer id) {
        if (menuService.removeById(id)) {
            return success("删除成功");
        }
        return fail("删除失败");
    }

    @PreAuthorize("hasAuthority('sys:menu:save')")
    @OperationLog
    @Operation(summary = "批量添加菜单")
    @PostMapping("/batch")
    public ApiResult<?> saveBatch(@RequestBody List<Menu> menus) {
        if (menuService.saveBatch(menus)) {
            return success("添加成功");
        }
        return fail("添加失败");
    }

    @PreAuthorize("hasAuthority('sys:menu:update')")
    @OperationLog
    @Operation(summary = "批量修改菜单")
    @PutMapping("/batch")
    public ApiResult<?> updateBatch(@RequestBody BatchParam<Menu> batchParam) {
        if (batchParam.update(menuService, "menu_id")) {
            return success("修改成功");
        }
        return fail("修改失败");
    }

    @PreAuthorize("hasAuthority('sys:menu:remove')")
    @OperationLog
    @Operation(summary = "批量删除菜单")
    @DeleteMapping("/batch")
    public ApiResult<?> removeBatch(@RequestBody List<Integer> ids) {
        if (menuService.removeByIds(ids)) {
            return success("删除成功");
        }
        return fail("删除失败");
    }

    @PreAuthorize("hasAuthority('sys:menu:remove')")
    @Operation(summary = "删除父级以下菜单")
    @DeleteMapping("/deleteParentMenu/{id}")
    public ApiResult<?> deleteParentMenu(@PathVariable("id") Integer id) {
      final List<Menu> list = menuService.list(new LambdaQueryWrapper<Menu>().eq(Menu::getParentId, id));
      if (CollectionUtils.isEmpty(list)) {
        menuService.removeById(id);
        return success("删除成功");
      }
      final Set<Integer> ids = list.stream().map(Menu::getMenuId).collect(Collectors.toSet());
      final List<Menu> list2 = menuService.list(new LambdaUpdateWrapper<Menu>().in(Menu::getParentId, ids));
      final Set<Integer> collect = list2.stream().map(Menu::getMenuId).collect(Collectors.toSet());
      if (!CollectionUtils.isEmpty(list2)) {
        ids.addAll(collect);
        final List<Menu> list3 = menuService.list(new LambdaUpdateWrapper<Menu>().in(Menu::getParentId, ids));
        final Set<Integer> collect1 = list3.stream().map(Menu::getMenuId).collect(Collectors.toSet());
        if (!CollectionUtils.isEmpty(collect1)) {
          ids.addAll(collect1);
        }
        ids.add(id);
        if (menuService.removeByIds(ids)) {
          return success("删除成功");
        }
      }
      ids.add(id);
      if (menuService.removeByIds(ids)) {
        return success("删除成功");
      }
      return fail("删除失败");
    }


    @Operation(summary = "菜单克隆")
    @PostMapping("/clone")
    public ApiResult<?> onClone(@RequestBody MenuParam param){
      final User loginUser = getLoginUser();
      if (loginUser == null) {
        return fail("请先登录");
      }
      if (!loginUser.getUsername().equals("superAdmin") && !loginUser.getUsername().equals("admin")) {
        return fail("只有超级管理员才能操作");
      }
      if(loginUser.getInstalled().equals(true) && ObjectUtil.isEmpty(param.getMenuId())){
        return fail("请先卸载插件");
      }
      if(menuService.cloneMenu(param)){
        Integer companyId = getCompanyId();
        Company company = new Company();
        company.setCompanyId(companyId);
        company.setPlanId(param.getTenantId());
        VersionParam versionParam = new VersionParam();
        versionParam.setLimit(1L);
        final PageResult<Version> result = versionService.pageRel(versionParam);
        if (!CollectionUtils.isEmpty(result.getList())) {
          Version version = result.getList().get(0);
          company.setVersionName(version.getVersionName());
          company.setVersionCode(version.getVersionCode());
        }
        companyService.updateById(company);
        loginUser.setInstalled(true);
        loginUser.setIsSuperAdmin(true);
        userService.updateById(loginUser);
        return success("安装成功");
      }
      return fail("安装失败");
    }

    @PreAuthorize("hasAuthority('sys:menu:update')")
    @Operation(summary = "安装插件")
    @GetMapping("/install/{id}")
    public ApiResult<?> install(@PathVariable("id") Integer id){
      if(menuService.install(id)){
        // 更新安装次数
//        final Plug plug = plugService.getOne(new LambdaQueryWrapper<Plug>().eq(Plug::getMenuId, id));
//        plug.setInstalls(plug.getInstalls() + 1);
//        plugService.updateById(plug);
        return success("安装成功");
      }
      return fail("安装失败",id);
    }

    /**
     * excel批量导入菜单
     */
    @PreAuthorize("hasAuthority('sys:menu:save')")
    @Operation(summary = "批量导入菜单")
    @Transactional(rollbackFor = {Exception.class})
    @PostMapping("/import")
    public ApiResult<?> importBatch(MultipartFile file) {
        ImportParams importParams = new ImportParams();
        try {
            System.out.println("=== 开始菜单导入流程 ===");

            // 检查导入前的菜单数据
            long beforeCount = menuService.count();
            System.out.println("导入前菜单总数: " + beforeCount);

            // 检查当前未删除的菜单
            List<Menu> undeletedMenus = menuService.list(new LambdaQueryWrapper<Menu>().eq(Menu::getDeleted, 0));
            System.out.println("当前未删除的菜单数: " + undeletedMenus.size());
            if (!undeletedMenus.isEmpty()) {
                System.out.println("未删除菜单列表:");
                for (Menu menu : undeletedMenus) {
                    System.out.println("  ID: " + menu.getMenuId() + ", 名称: " + menu.getTitle() +
                        ", 父级ID: " + menu.getParentId() + ", deleted: " + menu.getDeleted());
                }
            }

            // 第一步：永久删除已标记为 deleted=1 的记录
            boolean deleteResult = menuService.remove(new LambdaQueryWrapper<Menu>().eq(Menu::getDeleted, 1));
            System.out.println("已永久删除标记为deleted=1的菜单记录，结果: " + deleteResult);

            // 第二步：将现有未删除的记录（deleted=0）标记为 deleted=1
            if (!undeletedMenus.isEmpty()) {
                LambdaUpdateWrapper<Menu> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.eq(Menu::getDeleted, 0);
                updateWrapper.set(Menu::getDeleted, 1);
                boolean updateResult = menuService.update(updateWrapper);
                System.out.println("更新未删除菜单记录的结果: " + updateResult);
            }

            // 检查更新后的菜单数据
            long afterCleanupCount = menuService.count(new LambdaQueryWrapper<Menu>().eq(Menu::getDeleted, 0));
            System.out.println("清理后未标记删除的菜单数: " + afterCleanupCount);

            // 第三步：导入XLS文件的内容
            List<MenuImportParam> list = ExcelImportUtil.importExcel(file.getInputStream(), MenuImportParam.class, importParams);
            System.out.println("从Excel文件中读取到" + list.size() + "条菜单记录");

            // 存储原始parentId到菜单列表的映射关系
            Map<Integer, List<MenuImportParam>> menuGroups = new HashMap<>();
            // 存储原始ID到新菜单对象的映射关系（用于后续设置正确的parentId）
            Map<Integer, Menu> tempIdMapping = new HashMap<>();

            // 按parentId分组（处理null值）
            for (MenuImportParam param : list) {
                Integer parentId = param.getParentId() != null ? param.getParentId() : 0;
                menuGroups.computeIfAbsent(parentId, k -> new ArrayList<>()).add(param);
            }

            System.out.println("菜单分组情况:");
            for (Map.Entry<Integer, List<MenuImportParam>> entry : menuGroups.entrySet()) {
                System.out.println("  parentId=" + entry.getKey() + " 的菜单数: " + entry.getValue().size());
            }

            // 先创建所有父级菜单（parentId为0的菜单）
            List<MenuImportParam> rootMenus = menuGroups.getOrDefault(0, new ArrayList<>());
            List<Menu> createdRootMenus = new ArrayList<>();

            System.out.println("开始创建" + rootMenus.size() + "个根菜单");
            for (MenuImportParam param : rootMenus) {
                Menu menu = convertToMenu(param);
                menu.setParentId(0); // 根菜单的parentId为0
                menuService.save(menu);
                createdRootMenus.add(menu);
                System.out.println("创建根菜单: " + menu.getTitle() + ", ID: " + menu.getMenuId() + ", 原始ID: " + param.getMenuId());

                // 记录原始ID到新菜单的映射关系
                if (param.getMenuId() != null) {
                    tempIdMapping.put(param.getMenuId(), menu);
                }
            }

            // 递归创建子级菜单（注意：这里不再处理parentId=0的菜单，因为已经在上面处理过了）
            System.out.println("开始创建子级菜单（跳过根菜单）");
            // 只处理非根菜单的子级菜单
            for (Map.Entry<Integer, List<MenuImportParam>> entry : menuGroups.entrySet()) {
                Integer parentId = entry.getKey();
                if (parentId != 0) {  // 跳过根菜单（parentId=0）
                    System.out.println("处理parentId=" + parentId + "的子菜单");
                    createChildMenus(menuGroups, tempIdMapping, parentId);
                }
            }

            // 获取所有导入的菜单ID
            List<Integer> allImportedMenuIds = new ArrayList<>();
            for (Menu menu : tempIdMapping.values()) {
                allImportedMenuIds.add(menu.getMenuId());
            }

            System.out.println("总共导入了" + allImportedMenuIds.size() + "个菜单");

            // 显示导入的菜单详情
            if (!allImportedMenuIds.isEmpty()) {
                List<Menu> allImportedMenus = menuService.list(new LambdaQueryWrapper<Menu>()
                    .in(Menu::getMenuId, allImportedMenuIds)
                    .orderByAsc(Menu::getParentId, Menu::getSortNumber));
                System.out.println("导入的菜单详情:");
                for (Menu menu : allImportedMenus) {
                    System.out.println("  ID: " + menu.getMenuId() + ", 名称: " + menu.getTitle() +
                        ", 父级ID: " + menu.getParentId() + ", 类型: " + menu.getMenuType());
                }
            }

            // 为超级管理员配置菜单权限
            if (!allImportedMenuIds.isEmpty()) {
                List<Menu> allImportedMenus = menuService.list(new LambdaQueryWrapper<Menu>()
                    .in(Menu::getMenuId, allImportedMenuIds));
                System.out.println("为" + allImportedMenus.size() + "个菜单配置超级管理员权限");
                configureSuperAdminPermissionsForImportedMenus(allImportedMenus);
            }

            // 最终检查
            long finalCount = menuService.count();
            System.out.println("导入后菜单总数: " + finalCount);
            System.out.println("=== 菜单导入流程结束 ===");

            return success("成功导入" + list.size() + "条");
        } catch (Exception e) {
            e.printStackTrace();
            return fail("导入失败: " + e.getMessage());
        }
    }

    /**
     * 递归创建子级菜单
     * @param menuGroups 菜单分组
     * @param tempIdMapping 临时ID映射关系
     * @param originalParentId 原始父级ID
     */
    private void createChildMenus(Map<Integer, List<MenuImportParam>> menuGroups,
                                  Map<Integer, Menu> tempIdMapping,
                                  Integer originalParentId) {
        System.out.println(">>> 进入createChildMenus方法，处理originalParentId=" + originalParentId);

        // 特殊处理：originalParentId=0的情况已经在主方法中处理过了，这里不应该再处理
        if (originalParentId == 0) {
            System.out.println("  跳过originalParentId=0的处理（已在主方法中处理）");
            System.out.println("<<< 退出createChildMenus方法，处理originalParentId=" + originalParentId);
            return;
        }

        List<MenuImportParam> childMenus = menuGroups.get(originalParentId);
        if (childMenus == null || childMenus.isEmpty()) {
            System.out.println("  没有找到originalParentId=" + originalParentId + "的子菜单");
            System.out.println("<<< 退出createChildMenus方法，处理originalParentId=" + originalParentId);
            return;
        }

        // 获取新的父级菜单对象
        Menu parentMenu = tempIdMapping.get(originalParentId);
        if (parentMenu == null) {
            System.out.println("  未找到原始ID为" + originalParentId + "的父级菜单，跳过处理");
            System.out.println("<<< 退出createChildMenus方法，处理originalParentId=" + originalParentId);
            return;
        }

        Integer newParentId = parentMenu.getMenuId();

        System.out.println("  创建父级ID为" + originalParentId + "(新ID:" + newParentId + ")的子菜单，共" + childMenus.size() + "个");

        // 创建所有子菜单
        for (int i = 0; i < childMenus.size(); i++) {
            MenuImportParam param = childMenus.get(i);
            System.out.println("    处理第" + (i+1) + "个子菜单，原始ID: " + param.getMenuId() + ", 原始ParentId: " + param.getParentId());

            Menu menu = convertToMenu(param);
            menu.setParentId(newParentId);
            menuService.save(menu);

            System.out.println("    创建子菜单: " + menu.getTitle() + ", ID: " + menu.getMenuId() +
                ", 父级ID: " + menu.getParentId() + ", 原始ID: " + param.getMenuId());

            // 记录原始ID到新菜单的映射关系
            if (param.getMenuId() != null) {
                tempIdMapping.put(param.getMenuId(), menu);
            }

            // 递归创建当前菜单的子级菜单（使用原始ID作为下一个递归的父级ID）
            System.out.println("    递归调用createChildMenus，处理原始ID=" + param.getMenuId() + "的子菜单");
            createChildMenus(menuGroups, tempIdMapping, param.getMenuId());
        }

        System.out.println("<<< 退出createChildMenus方法，处理originalParentId=" + originalParentId);
    }

    /**
     * 将MenuImportParam转换为Menu实体
     * @param param MenuImportParam对象
     * @return Menu实体
     */
    private Menu convertToMenu(MenuImportParam param) {
        Menu menu = new Menu();
        menu.setParentId(param.getParentId());
        menu.setTitle(param.getTitle());
        menu.setPath(param.getPath());
        menu.setComponent(param.getComponent());
        menu.setModules(param.getModules());
        menu.setModulesUrl(param.getModulesUrl());
        menu.setMenuType(param.getMenuType());
        menu.setSortNumber(param.getSortNumber() != null ? param.getSortNumber() : 0);
        menu.setAuthority(param.getAuthority());
        menu.setIcon(param.getIcon());
        menu.setHide(param.getHide());
        menu.setAppId(param.getAppId());
        menu.setTenantId(param.getTenantId());
        menu.setDeleted(0); // 新导入的数据deleted设为0
        return menu;
    }

    /**
     * 为超级管理员配置导入菜单的权限
     * @param importedMenus 导入的菜单列表
     */
    private void configureSuperAdminPermissionsForImportedMenus(List<Menu> importedMenus) {
        try {
            // 1.查找当前租户的超管权限的roleId
            final Role superAdmin = roleService.getOne(new LambdaQueryWrapper<Role>().eq(Role::getRoleCode, "superAdmin"));
            if (superAdmin == null) {
                System.out.println("未找到superAdmin角色");
                return;
            }

            final Integer roleId = superAdmin.getRoleId();
            final Integer tenantId = superAdmin.getTenantId();

            // 为所有导入的菜单配置权限
            for (Menu menu : importedMenus) {
                RoleMenu roleMenu = new RoleMenu();
                roleMenu.setRoleId(roleId);
                roleMenu.setMenuId(menu.getMenuId());
                roleMenu.setTenantId(tenantId);
                roleMenuService.save(roleMenu);
            }

            // 调整根菜单的排序（如果有根菜单的话）
            for (Menu menu : importedMenus) {
                if (menu.getParentId() == 0) {
                    menu.setSortNumber(0);
                    menuService.updateById(menu);
                    break;
                }
            }

            System.out.println("为超级管理员配置菜单权限成功，共配置了" + importedMenus.size() + "个菜单");
        } catch (Exception e) {
            System.err.println("为超级管理员配置菜单权限失败: " + e.getMessage());
            e.printStackTrace();
        }
    }
}
