package com.gci.boot.modules.system.controller;


import cn.hutool.json.JSONArray;
import com.alibaba.excel.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.gci.boot.common.log.annotation.AddSysLog;
import com.gci.boot.common.util.ParamsCheckUtil;
import com.gci.boot.common.util.QueryWrapperUtil;
import com.gci.boot.constant.CommonConstant;
import com.gci.boot.common.util.MD5Util;
import com.gci.boot.common.vo.Result;
import com.gci.boot.modules.system.entity.SysPermission;
import com.gci.boot.modules.system.entity.SysRolePermission;
import com.gci.boot.modules.system.vo.SysPermissionTree;
import com.gci.boot.modules.system.vo.TreeModel;
import com.gci.boot.modules.system.service.ISysPermissionService;
import com.gci.boot.modules.system.service.ISysRolePermissionService;
import com.gci.boot.modules.system.shiro.vo.DefContants;
import com.gci.boot.modules.system.util.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 菜单权限表 前端控制器
 * </p>
 *
 * @author chenzhiwei
 * @since 2023-08-18
 */
@RestController
@RequestMapping("/sys/permission")
@Slf4j
public class SysPermissionController {
    @Autowired
    private ISysPermissionService sysPermissionService;
    @Autowired
    private ISysRolePermissionService sysRolePermissionService;

    /**
     * 系统菜单列表(一级菜单)
     *
     * @return
     */
    @AddSysLog("查询一级菜单")
    @GetMapping("/getSystemMenuList")
    public Result<List<SysPermissionTree>> getSystemMenuList(SysPermission permission) {
        try {
            permission.setMenuType(CommonConstant.MENU_TYPE_MAIN);
            QueryWrapper<SysPermission> query = QueryWrapperUtil.builder()
                    .table(SysPermission.class)
                    .like(SysPermission::getName)
                    .orderByAsc(SysPermission::getSortNo)
                    .buildFromObject(permission);
            List<SysPermission> list = sysPermissionService.list(query);
            List<SysPermissionTree> sysPermissionTreeList = new ArrayList<SysPermissionTree>();
            for(SysPermission sysPermission : list){
                SysPermissionTree sysPermissionTree = new SysPermissionTree(sysPermission);
                sysPermissionTreeList.add(sysPermissionTree);
            }
            return Result.ok(sysPermissionTreeList);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Result.error("获取菜单失败！");
        }
    }

    /**
     * 查询子菜单
     * @param parentId
     * @return
     */
    @AddSysLog("查询子菜单")
    @GetMapping( "/getSystemSubmenu")
    public Result<List<SysPermissionTree>> getSystemSubmenu(@RequestParam("parentId") String parentId){
        LambdaQueryWrapper<SysPermission> query = new LambdaQueryWrapper<>();
        query.eq(SysPermission::getParentId,parentId);
        query.orderByAsc(SysPermission::getSortNo);
        List<SysPermission> list = sysPermissionService.list(query);
        List<SysPermissionTree> sysPermissionTreeList = new ArrayList<SysPermissionTree>();
        for(SysPermission sysPermission : list){
            SysPermissionTree sysPermissionTree = new SysPermissionTree(sysPermission);
            sysPermissionTreeList.add(sysPermissionTree);
        }
        return Result.ok(sysPermissionTreeList);
    }

    /**
     * 获取全部的权限树
     *
     * @return
     */
    @AddSysLog("查询菜单树")
    @GetMapping("/queryTreeList")
    public Result<Map<String, Object>> queryTreeList() {
        // 全部权限ids
        List<String> ids = new ArrayList<>();
        LambdaQueryWrapper<SysPermission> query = new LambdaQueryWrapper<SysPermission>();
        query.orderByAsc(SysPermission::getSortNo);
        List<SysPermission> list = sysPermissionService.list(query);
        for (SysPermission sysPer : list) {
            ids.add(sysPer.getId());
        }
        List<TreeModel> treeList = new ArrayList<>();
        getTreeModelList(treeList, list, null);

        Map<String, Object> resMap = new HashMap<String, Object>();
        resMap.put("treeList", treeList); // 全部树节点数据
        resMap.put("ids", ids);// 全部树ids
        return Result.ok(resMap);
    }

    /**
     * 查询用户拥有的菜单权限和按钮权限（根据TOKEN）
     *
     * @return
     */
    @GetMapping("/getUserPermissionByToken")
    public Result<?> getUserPermissionByToken(String token, HttpServletRequest request) {
            if(StringUtils.isBlank(token)){
                token = request.getHeader(DefContants.X_ACCESS_TOKEN);
            }
            if (StringUtils.isBlank(token)) {
                return Result.error("TOKEN不允许为空！");
            }
            log.info(" ------ 通过令牌获取用户拥有的访问菜单 ---- TOKEN ------ " + token);
            String username = JwtUtil.getUsername(token);
            List<SysPermission> metaList = sysPermissionService.queryByUser(username);
            //添加首页路由
            if (!metaList.stream().map(SysPermission::getName).anyMatch(name -> "首页".equals(name))) {
                List<SysPermission> menus = sysPermissionService.lambdaQuery().eq(SysPermission::getName, "首页").list();
                if(menus.size() > 0) {
                    metaList.add(0, menus.get(0));
                }
            }
            Map<String, Object> map = new LinkedHashMap<>();
            List<Map<String, Object>> menuArray = new ArrayList();
            this.getPermissionArray(menuArray, metaList, null);
            List<Map<String, Object>> authArray = new ArrayList();
            this.getAuthArray(authArray, metaList);
            //查询所有的权限
            LambdaQueryWrapper<SysPermission> query = new LambdaQueryWrapper<SysPermission>();
            List<SysPermission> allAuthList = sysPermissionService.lambdaQuery()
                    .eq(SysPermission::getMenuType, CommonConstant.MENU_TYPE_BUTTON)
                    .list();
            List<Map<String, Object>> allauthArray = new ArrayList();
            this.getAllAuthArray(allauthArray, allAuthList);
            //路由菜单
            map.put("menu", menuArray);
            //按钮权限（用户拥有的权限集合）
            map.put("auth", authArray);
            //全部权限配置集合（按钮权限，访问权限）
            map.put("allAuth", allauthArray);

            return Result.ok(map);
    }

    /**
     * 添加菜单
     * @param permission
     * @return
     */
    @AddSysLog("添加菜单")
    @PostMapping("/add")
    public Result<SysPermission> add(@RequestBody SysPermission permission) {
        ParamsCheckUtil.paramsAssert().notBlank(permission.getName(), "【菜单名称】不能为空！");
        sysPermissionService.addPermission(permission);
        return Result.ok("添加成功！");
    }

    /**
     * 编辑菜单
     * @param permission
     * @return
     */
    @AddSysLog("编辑菜单")
    @PutMapping("/edit")
    public Result<SysPermission> edit(@RequestBody SysPermission permission) {
        ParamsCheckUtil.paramsAssert().notBlank(permission.getName(), "【菜单名称】不能为空！");
        sysPermissionService.editPermission(permission);
        return Result.ok("修改成功！");
    }

    /**
     * 删除菜单
     * @param id
     * @return
     */
    @AddSysLog("删除菜单")
    @DeleteMapping("/delete")
    public Result<SysPermission> delete(String id) {
        sysPermissionService.deletePermission(id);
        return Result.ok("删除成功!");
    }

    /**
     * 获取菜单数组
     *
     * @param array
     * @param metaList
     * @param parentMap
     */
    private void getPermissionArray(List<Map<String,Object>> array, List<SysPermission> metaList, Map<String, Object> parentMap) {
        for (SysPermission permission : metaList) {
            if (permission.getMenuType() == null) {
                continue;
            }
            String tempPid = permission.getParentId();
            Map<String, Object> map = getPermissionMap(permission);
            if (map == null) {
                continue;
            }
            if (parentMap == null && StringUtils.isBlank(tempPid)) {
                array.add(map);
                if (permission.getIsLeaf() == null || permission.getIsLeaf() != 1) {
                    getPermissionArray(array, metaList, map);
                }
            } else if (parentMap != null && StringUtils.isNotBlank(tempPid) && tempPid.equals(parentMap.get("id"))) {
                // 类型( 0：一级菜单 1：子菜单 2：按钮 )
                if (permission.getMenuType().equals(CommonConstant.MENU_TYPE_BUTTON)) {
                    Map<String, Object> metaJson = (Map<String, Object>) parentMap.get("meta");
                    if (metaJson.containsKey("permissionList")) {
                        ((List<Map<String, Object>>) metaJson.get("permissionList")).add(map);
                    } else {
                        JSONArray permissionList = new JSONArray();
                        permissionList.add(map);
                        metaJson.put("permissionList", permissionList);
                    }
                    // 类型( 0：一级菜单 1：子菜单 2：按钮 )
                } else if (permission.getMenuType().equals(CommonConstant.MENU_TYPE_SUB) || permission.getMenuType().equals(CommonConstant.MENU_TYPE_MAIN)) {
                    if (parentMap.containsKey("children")) {
                        ((List<Map<String, Object>>) parentMap.get("children")).add(map);
                    } else {
                        List<Map<String, Object>> children = new ArrayList<>();
                        children.add(map);
                        parentMap.put("children", children);
                    }

                    if (permission.getIsLeaf() == null || permission.getIsLeaf() != 1) {
                        getPermissionArray(array, metaList, map);
                    }
                }
            }

        }
    }

    /**
     *  获取权限数组
     * @param array
     * @param allList
     */
    private void getAllAuthArray(List<Map<String, Object>> array,List<SysPermission> allList) {
        Map<String, Object> map;
        for (SysPermission permission : allList) {
            map = new LinkedHashMap<>();
            map.put("action", permission.getPerms());
            map.put("status", permission.getStatus());
            map.put("type", permission.getPermsType());
            map.put("describe", permission.getName());
            array.add(map);
        }
    }

    /**
     *  获取权限数组
     * @param array
     * @param metaList
     */
    private void getAuthArray(List<Map<String, Object>> array,List<SysPermission> metaList) {
        for (SysPermission permission : metaList) {
            if(permission.getMenuType()==null) {
                continue;
            }
            Map<String, Object> map = null;
            if(permission.getMenuType().equals(CommonConstant.MENU_TYPE_BUTTON) &&CommonConstant.STATUS_1.equals(permission.getStatus())) {
                map = new LinkedHashMap<>();
                map.put("action", permission.getPerms());
                map.put("type", permission.getPermsType());
                map.put("describe", permission.getName());
                array.add(map);
            }
        }
    }

    /**
     * 根据菜单配置生成路由json
     *
     * @param permission
     * @return
     */
    private Map<String, Object> getPermissionMap(SysPermission permission) {
        Map<String, Object> map = new LinkedHashMap<>();
        // 类型(0：一级菜单 1：子菜单 2：按钮)
        if (permission.getMenuType().equals(CommonConstant.MENU_TYPE_BUTTON)) {
            return null;
        } else if (permission.getMenuType().equals(CommonConstant.MENU_TYPE_MAIN) || permission.getMenuType().equals(CommonConstant.MENU_TYPE_SUB)) {
            map.put("id", permission.getId());
            if (isWWWHttpUrl(permission.getUrl())) {
                map.put("path", MD5Util.MD5Encode(permission.getUrl(), "utf-8"));
            } else {
                map.put("path", permission.getUrl());
            }

            // 重要规则：路由name (通过URL生成路由name,路由name供前端开发，页面跳转使用)
            if (StringUtils.isNotBlank(permission.getComponentName())) {
                map.put("name", permission.getComponentName());
            } else {
                map.put("name", urlToRouteName(permission.getUrl()));
            }

            map.put("component", permission.getComponent());
            Map<String, Object> meta = new LinkedHashMap<>();

            meta.put("title", permission.getName());
            if (StringUtils.isBlank(permission.getParentId())) {
                // 一级菜单跳转地址
                map.put("redirect", permission.getRedirect());
                if (StringUtils.isNotBlank(permission.getIcon())) {
                    meta.put("icon", permission.getIcon());
                }
            } else {
                if (StringUtils.isNotBlank(permission.getIcon())) {
                    meta.put("icon", permission.getIcon());
                }
            }
            if (isWWWHttpUrl(permission.getUrl())) {
                meta.put("url", permission.getUrl());
            }
            map.put("meta", meta);
            map.put("hidden", permission.getHidden());
            map.put("internalOrExternal", permission.getInternalOrExternal());
        }

        return map;
    }

    /**
     * 判断是否外网URL 例如： http://localhost:8080/jeecg-boot/swagger-ui.html#/ 支持特殊格式： {{
     * window._CONFIG['domianURL'] }}/druid/ {{ JS代码片段 }}，前台解析会自动执行JS代码片段
     *
     * @return
     */
    private boolean isWWWHttpUrl(String url) {
        if (url != null && (url.startsWith("http://") || url.startsWith("https://") || url.startsWith("{{"))) {
            return true;
        }
        return false;
    }

    /**
     * 通过URL生成路由name（去掉URL前缀斜杠，替换内容中的斜杠‘/’为-） 举例： URL = /isystem/role RouteName =
     * isystem-role
     *
     * @return
     */
    private String urlToRouteName(String url) {
        if (StringUtils.isNotBlank(url)) {
            if (url.startsWith("/")) {
                url = url.substring(1);
            }
            url = url.replace("/", "-");

            // 特殊标记
            url = url.replace(":", "@");
            return url;
        } else {
            return null;
        }
    }


    private void getTreeModelList(List<TreeModel> treeList, List<SysPermission> metaList, TreeModel temp) {
        for (SysPermission permission : metaList) {
            String tempPid = permission.getParentId();
            TreeModel tree = new TreeModel(permission);
            if (temp == null && StringUtils.isBlank(tempPid)) {
                treeList.add(tree);
                if (!tree.getIsLeaf()) {
                    getTreeModelList(treeList, metaList, tree);
                }
            } else if (temp != null && tempPid != null && tempPid.equals(temp.getKey())) {
                temp.getChildren().add(tree);
                if (!tree.getIsLeaf()) {
                    getTreeModelList(treeList, metaList, tree);
                }
            }
        }
    }

    /**
     * 保存角色授权
     *
     * @return
     */
    @AddSysLog("保存角色授权")
    @PostMapping("/saveRolePermission")
    public Result<String> saveRolePermission(@RequestBody Map<String, String> params) {
        try {
            String roleId = params.get("roleId");
            String permissionIds = params.get("permissionIds");
            String lastPermissionIds = params.get("lastpermissionIds");
            this.sysRolePermissionService.saveRolePermission(roleId, permissionIds, lastPermissionIds);
            return Result.ok("保存成功！");
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Result.error("授权失败！");
        }
    }

    /**
     * 查询角色权限
     *
     * @return
     */
    @AddSysLog("查询角色权限")
    @GetMapping( "/queryRolePermission")
    public Result<List<String>> queryRolePermission(String roleId) {
            List<SysRolePermission> list = sysRolePermissionService.lambdaQuery().eq(SysRolePermission::getRoleId, roleId).list();
            return Result.ok(list.stream().map(SysRolePermission -> String.valueOf(SysRolePermission.getPermissionId())).collect(Collectors.toList()));
    }
}
