package com.ho.user.controller;


import cn.hutool.core.util.StrUtil;
import com.ho.common.tools.annotation.LogAnnotation;
import com.ho.common.tools.constant.CommonConstant;
import com.ho.common.tools.constant.ContextConstant;
import com.ho.common.tools.constant.RedisKeyConstant;
import com.ho.common.tools.entity.SysPermission;
import com.ho.common.tools.entity.UserDetailRespVO;
import com.ho.common.tools.exception.BaseResponseCode;
import com.ho.common.tools.exception.BusinessException;
import com.ho.common.tools.exception.DataResult;
import com.ho.common.tools.service.RedisService;
import com.ho.user.api.entity.PermStationRelation;
import com.ho.user.api.vo.req.QueryPermissionReqVo;
import com.ho.user.entity.PermissionRespNode;
import com.ho.user.service.PermissionService;
import com.ho.user.service.RedisUpdateService;
import com.ho.user.vo.req.PermissionAddReqVO;
import com.ho.user.vo.req.PermissionUpdateReqVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.List;

/**
 * 权限入口
 */
@RequestMapping(ContextConstant.SYS + "permission")
@RestController
@Api(tags = "系统模块-菜单权限管理")
@Slf4j
public class PermissionController {

    @Autowired
    private PermissionService permissionService;

    @Autowired
    private RedisService redisService;

    @Autowired
    RedisUpdateService redisUpdateService;

    @Autowired
    RedissonClient redissonClient;

    @GetMapping("{id}")
    @ApiOperation(value = "查询菜单权限接口")
    //@LogAnnotation(title = "菜单权限管理",action = "查询菜单权限")
    //@RequiresPermissions("sys:permission:detail")
    public DataResult<SysPermission> detailInfo(@PathVariable("id") Integer id) {
        DataResult<SysPermission> result = DataResult.success();
        result.setData(permissionService.detailInfo(id));
        return result;
    }

    @PostMapping("tree/all")
    @ApiOperation(value = "获取所有目录菜单树接口")
    //@LogAnnotation(title = "菜单权限管理",action = "获取所有目录菜单树")
    //@RequiresPermissions(value = {"sys:role:update","sys:role:add"},logical = Logical.OR)
    public DataResult<List<PermissionRespNode>> getAllPermissionTree(@RequestBody(required = false) @Valid QueryPermissionReqVo query) {
        DataResult<List<PermissionRespNode>> result = DataResult.success();
        if (query == null) {
            query = new QueryPermissionReqVo();
        }
        result.setData(permissionService.selectAllByTree(query, null, null));
        return result;
    }

    @PostMapping("all/get")
    @ApiOperation(value = "获取所有菜单(跟当前登录人没有关系)")
    public DataResult<List<PermissionRespNode>> getAll() {
        DataResult<List<PermissionRespNode>> result = DataResult.success();
        QueryPermissionReqVo query = new QueryPermissionReqVo();
        result.setData(permissionService.getAll(query));
        return result;
    }

    @PostMapping("all/enabledType")
    @ApiOperation(value = "角色管理获取所有启用及按钮类型菜单树接口")
    public DataResult<List<PermissionRespNode>> getSelectRoleAll() {
        DataResult<List<PermissionRespNode>> result = DataResult.success();
        QueryPermissionReqVo query = new QueryPermissionReqVo();
        result.setData(permissionService.selectAllByTree(query, null, "enableType"));
        return result;
    }

    @GetMapping("all/enabled")
    @ApiOperation(value = "获取所有启用目录菜单树接口")
    public DataResult<List<PermissionRespNode>> getSelectAllByStatus() {
        DataResult<List<PermissionRespNode>> result = DataResult.success();
        QueryPermissionReqVo query = new QueryPermissionReqVo();
        result.setData(permissionService.selectAllByTree(query, "enableStatus", null));
        return result;
    }

    @PostMapping("add")
    @ApiOperation(value = "新增菜单权限接口")
    @LogAnnotation(title = "菜单权限管理", action = "新增菜单权限")
    @RequiresPermissions("sys:permission:add")
    public DataResult<SysPermission> addPermission(@RequestBody @Valid PermissionAddReqVO vo, HttpServletRequest request) {
        String token = request.getHeader(RedisKeyConstant.User.ACCESS_TOKEN);
        String userTokenKey = RedisKeyConstant.User.TOKEN + token;
        UserDetailRespVO user = (UserDetailRespVO) redisService.get(userTokenKey);
        //权限标识如果传了值,就判断是否有相同的
        if (!StrUtil.isBlank(vo.getPerms())) {
            SysPermission sysPermission = permissionService.selectByPerms(vo.getPerms());
            if (sysPermission != null) {
                throw new BusinessException(BaseResponseCode.PERMISSION_ALREADY_EXISTS);
            }
        }
        //增加之前判断它所属的父节点的删除状态以及启用状态
        // 删除状态：不能添加子节点   0 已删除
        //不可启用状态 ：进行提示     0 不启用

        //如果不是顶级节点
        if (!CommonConstant.TOP_PARENT_ID.equals(vo.getPid())) {
            SysPermission sysPermission = permissionService.selectByPrimaryKey(vo.getPid());
            //如果是删除状态
            if (CommonConstant.DELETED_FLAG.equals(sysPermission.getDeleted())) {
                throw new BusinessException(BaseResponseCode.PARENT_MENU_DELENTION_STATUS);
            }
            //如果是未启用状态
            if (CommonConstant.ZERO.equals(sysPermission.getStatus())) {
                throw new BusinessException(BaseResponseCode.PARENT_MENU_NOT_ADD_ENABLED);
            }
        }
        //如果是顶级菜单,那么 show必填
        if (CommonConstant.TOP_PARENT_ID.equals(vo.getPid())) {
            //如果等于3（按钮）则不判断show
            if (CommonConstant.BUTTON_FLAG.equals(vo.getType())) {
                //判断新增父级节点是的type是否为按钮，如果是按钮的话，则进行提示
                if (CommonConstant.BUTTON_FLAG.equals(vo.getType())) {
                    throw new BusinessException(BaseResponseCode.PARENT_NODE_TYPE_NOT_BUTTON);
                }
            } else {
                if (StringUtils.isEmpty(vo.getShow())
                        || (!CommonConstant.MenuShowType.ALL.equals(vo.getShow())
                        && !CommonConstant.MenuShowType.PC.equals(vo.getShow())
                        && !CommonConstant.MenuShowType.APP.equals(vo.getShow()))
                ) {
                    throw new BusinessException(BaseResponseCode.MENU_SHOW_TYPE_NOT_RIGHT);
                }
            }
        }
        //如果是顶级菜单,那么名称不能为"系统管理",因为”系统管理“有特殊用处，用于控制平台管理员的查询数据
        /*if (CommonConstant.TOP_PARENT_ID.equals(vo.getPid()) && CommonConstant.SYS_MENU_NAME.equals(vo.getName())) {
            throw new BusinessException(BaseResponseCode.SYS_MENU_NAME_NOT_RIGHT);
        }*/
        //如果是顶级菜单,那么名称不能为"菜单管理"
        if (CommonConstant.TOP_PARENT_ID.equals(vo.getPid()) && CommonConstant.PERMISSION_MENU_NAME.equals(vo.getName())) {
            throw new BusinessException(BaseResponseCode.SYS_MENU_NAME_NOT_RIGHT);
        }
        //增加分布式锁
        //定义锁
        RLock lock = null;
        SysPermission sysPermission = null;
        try {
            lock = redissonClient.getLock(RedisKeyConstant.LOCK_KEY_PERMISSION);
            //获取锁,没有获取到锁的阻塞在lock.lock() 这行
            lock.lock();
            sysPermission = permissionService.addPermission(vo);
            //新增完菜单后需要更新超管缓存的菜单列表
       /* try {
            redisUpdateService.updateSuperPermsCache();
        } catch (Exception e) {
            log.error("更新超管缓存的菜单列表出错");
        }*/
        } finally {
            if (lock != null && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return DataResult.success(sysPermission);
    }

    @PutMapping("update")
    @ApiOperation(value = "更新菜单权限接口")
    @LogAnnotation(title = "菜单权限管理", action = "更新菜单权限")
    @RequiresPermissions("sys:permission:update")
    public DataResult updatePermission(@RequestBody @Valid PermissionUpdateReqVO vo) {
        //判断其他id是否有该perms的数据
        //查询系统管理那个记录
        SysPermission sysManageMenu = permissionService.findSysManageMenu();
        //顶级菜单的 系统管理不能被修改
        if (sysManageMenu != null && sysManageMenu.getId().equals(vo.getId())) {
            //判断是否要更改为禁用，更改为禁用时进行提示
            if (!CommonConstant.STATUS_FLAG.equals(vo.getStatus())) {
                throw new BusinessException(BaseResponseCode.SYS_MENU_NAME_STATUS_CANNOT);
            }
            //只允许改图标
            PermissionUpdateReqVO updateReqVO = new PermissionUpdateReqVO();
            updateReqVO.setId(vo.getId());
            updateReqVO.setIcon(vo.getIcon());
            updateReqVO.setOrderNum(vo.getOrderNum());
            updateReqVO.setPid(vo.getPid());
            updateReqVO.setShow(vo.getShow());
            updateReqVO.setType(CommonConstant.MENU_FLAG);
            updateReqVO.setName(vo.getName());
            vo = updateReqVO;
            //throw new BusinessException(BaseResponseCode.SYS_MENU_NAME_CANNOT_MODIFY);
            //permissionService.updateLittle(updateVo);
        }
        //如果是顶级菜单,那么 show必填
        if (CommonConstant.TOP_PARENT_ID.equals(vo.getPid())) {
            //是按钮不用判断show
            if (!CommonConstant.BUTTON_FLAG.equals(vo.getType())) {
                if (StringUtils.isEmpty(vo.getShow())
                        || (!CommonConstant.MenuShowType.ALL.equals(vo.getShow())
                        && !CommonConstant.MenuShowType.PC.equals(vo.getShow())
                        && !CommonConstant.MenuShowType.APP.equals(vo.getShow()))
                ) {
                    throw new BusinessException(BaseResponseCode.MENU_SHOW_TYPE_NOT_RIGHT);
                }
            }

        }
        //查看是否是菜单管理，菜单管理也不可以禁用
        SysPermission theMenu = permissionService.findTheMenu();
        if (theMenu != null && theMenu.getId().equals(vo.getId())) {
            //判断是否要更改为禁用，更改为禁用时进行提示
            if (!CommonConstant.STATUS_FLAG.equals(vo.getStatus())) {
                throw new BusinessException(BaseResponseCode.MENU_NAME_STATUS_CANNOT);
            }
        }
        //定义锁
        RLock lock = null;
        try {
            lock = redissonClient.getLock(RedisKeyConstant.LOCK_KEY_PERMISSION);
            //获取锁,没有获取到锁的阻塞在lock.lock() 这行
            lock.lock();
            permissionService.updatePermission(vo);
        } finally {
            if (lock != null && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        //如果是修改菜单状态,还会修改子集菜单
        //更新超管菜单
        // redisUpdateService.updateSuperPermsCache();
        return DataResult.success(vo);


    }

    @DeleteMapping("{id}")
    @ApiOperation(value = "删除菜单权限接口")
    @LogAnnotation(title = "菜单权限管理", action = "删除菜单权限")
    @RequiresPermissions("sys:permission:deleted")
    public DataResult deleted(@PathVariable("id") Integer id) {
        DataResult result = DataResult.success();
        //查询系统管理那个记录
        SysPermission sysManageMenu = permissionService.findSysManageMenu();
        //顶级菜单的 系统管理不能被修改
        if (sysManageMenu != null && sysManageMenu.getId().equals(id)) {
            throw new BusinessException(BaseResponseCode.SYS_MENU_NAME_CANNOT_MODIFY);
        }
        //判断是否为menu的数据，如果是则不能被删除
        SysPermission theMenu = permissionService.findTheMenu();
        if (theMenu != null && theMenu.getId().equals(id)) {
            throw new BusinessException(BaseResponseCode.SYS_MENU_NOT_DELETE_MENU);
        }
        //增加分布式锁
        //定义锁
        RLock lock = null;
        try {
            lock = redissonClient.getLock(RedisKeyConstant.LOCK_KEY_PERMISSION);
            //获取锁,没有获取到锁的阻塞在lock.lock() 这行
            lock.lock();
            permissionService.deleted(id);
        } finally {
            if (lock != null && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        //更新超管菜单
        // redisUpdateService.updateSuperPermsCache();
        return result;
    }

    //根据电站查询该电站的专属菜单
    @PostMapping("per/exclusiveMenu")
    @ApiOperation(value = "根据电站查询该电站的专属菜单")
    public DataResult<List<PermissionRespNode>> getStationPer(@RequestBody PermStationRelation permStationRelation, HttpServletRequest request) {
        String token = request.getHeader(RedisKeyConstant.User.ACCESS_TOKEN);
        String userTokenKey = RedisKeyConstant.User.TOKEN + token;
        String lang=request.getHeader(CommonConstant.LANG);
        UserDetailRespVO user = (UserDetailRespVO) redisService.get(userTokenKey);
        DataResult<List<PermissionRespNode>> result = DataResult.success();
        result.setData(permissionService.getStationPer(permStationRelation.getStationId(),user,lang));
        return result;
    }
}
