package com.iformall.controller.sys;

import com.iformall.annotation.SystemControllerLog;
import com.iformall.common.ErrorCode;
import com.iformall.common.Result;
import com.iformall.common.ResultData;
import com.iformall.controller.base.BaseController;
import com.iformall.domain.po.MallPermission;
import com.iformall.domain.po.MallRole;
import com.iformall.domain.po.MallRolePermission;
import com.iformall.domain.po.MallUserInfo;
import com.iformall.enums.EnumPermissionType;
import com.iformall.exception.MallinkException;
import com.iformall.mapper.MallMenuMapper;
import com.iformall.mapper.MallPermissionMapper;
import com.iformall.service.MallPermissionService;
import com.iformall.service.MallRolePermissionService;
import com.iformall.service.MallRoleService;
import com.iformall.service.MallUserInfoService;
import com.iformall.utils.Constant;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.util.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.*;

/**
 * @author Stormeye Wu
 * @date 2019-04-20.
 */
@RestController
@RequestMapping("menu")
public class SysMenuController extends BaseController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private MallPermissionService mallPermissionService;

    @Autowired
    private MallUserInfoService mallUserInfoService;

    @Autowired
    private MallRoleService mallRoleService;

    @Autowired
    private MallRolePermissionService mallRolePermissionService;

    @Autowired
    private MallMenuMapper mallMenuMapper;

    @Autowired
    private MallPermissionMapper mallPermissionMapper;

    @ApiOperation("导航菜单")
    @GetMapping("/nav")
    public ResultData nav(){
        logger.debug("[" + getIpAddr() + "] MallPermissionController::nav");
        MallUserInfo user = getUser();
        List<MallPermission> menuList = mallPermissionService.getUserMenuList(user, 0L, true);
        Set<String> permissions = mallUserInfoService.getUserPermissions(user);
        Map map = new HashMap<>();
        map.put("menuList", menuList);
        map.put("permissions", permissions);
        return new ResultData(map);
    }

    @ApiOperation("所有菜单列表")
    @GetMapping("list")
    //@RequiresPermissions("sys:menu:list")
    @SystemControllerLog(description = "用户管理-权限")
    public ResultData getList() {
        logger.debug("[" + getIpAddr() + "] MallPermissionController::list");
        MallUserInfo user = getUser();
        List<MallPermission> menuList = mallPermissionService.getUserMenuList(user, 0L, false);;
        Set<String> permissions = mallUserInfoService.getUserPermissions(user);
        Map map = new HashMap<>();
        map.put("menuList", menuList);
        map.put("permissions", permissions);
        return new ResultData(map);
    }

    @ApiOperation("添加菜单/权限")
    @PostMapping("add")
    //@RequiresPermissions("sys:menu:save")
    @SystemControllerLog(description = "用户管理-权限添加")
    public ResultData createPermission(MallPermission mallPermission) {
        logger.debug("[" + getIpAddr() + "] MallPermissionController::createPermission");
        Assert.notNull(mallPermission.getName(), "用户名不能为空");
        // 数据校验
        verifyForm(mallPermission);

        mallPermissionService.saveOrUpdate(mallPermission);
        return new ResultData(mallPermission.getId());
    }

    @ApiOperation("更新菜单/权限")
    @PostMapping("update")
    //@RequiresPermissions("sys:menu:update")
    @SystemControllerLog(description = "用户管理-权限更新")
    public ResultData updatePermission(MallPermission sysPermission) {
        logger.debug("[" + getIpAddr() + "] MallPermissionController::updatePermission");
        // 数据校验
        verifyForm(sysPermission);

        mallPermissionService.saveOrUpdate(sysPermission);
        return new ResultData();
    }

    @ApiOperation("删除菜单/权限")
    @GetMapping("/del")
    //@RequiresPermissions("sys:menu:delete")
    @SystemControllerLog(description = "用户管理-权限删除")
    public ResultData delete(Long id) {
        logger.debug("[" + getIpAddr() + "] MallPermissionController::delete");
        if(id <= Constant.SYS_MENU_MAX) {
            logger.error(ErrorCode.MENU_SYS_NOT_DEL.getMessage());
            return new ResultData(ErrorCode.MENU_SYS_NOT_DEL);
        }
        //判断是否有子菜单或按钮
        List<MallPermission> menuList = mallPermissionService.getByParentId(id);
        if(menuList.size() > 0){
            logger.error(ErrorCode.MENU_CHILD_NOT_DEL.getMessage());
            return new ResultData(ErrorCode.MENU_CHILD_NOT_DEL);
        }
        mallPermissionService.deleteById(id);
        return new ResultData(Result.SUCCESS, "删除成功");
    }

    @ApiOperation("菜单信息")
    @GetMapping("/findById")
    //@RequiresPermissions("sys:menu:info")
    @SystemControllerLog(description = "用户管理-权限查找")
    public ResultData findById(Long id) {
        logger.debug("[" + getIpAddr() + "] MallPermissionController::findById");
        return new ResultData(Result.SUCCESS, "成功", mallPermissionService.getById(id));
    }

    @ApiOperation("用户菜单权限升级")
    @GetMapping("/upgradeMenus")
    //@RequiresPermissions("sys:menu:info")
    @SystemControllerLog(description = "用户管理-权限升级")
    public ResultData upgradeMenus() {
        logger.debug("[" + getIpAddr() + "] MallPermissionController::upgradeMenus");
        MallUserInfo userInfo = getUser();
        if(userInfo.isFmSuperAdmin()) {
            adminMenuUpgrade();
            return new ResultData();
        }
        return new ResultData(ErrorCode.USER_NO_PERMISSION);
    }

    private void adminMenuUpgrade() {
        // 1. 获取已有管理员
        MallRole mrQ = new MallRole();
        mrQ.setName("系统管理员");
        mrQ.setAvailable("0");
        List<MallRole> mallRoleList = mallRoleService.getList(mrQ);
        // 2. 获取全部permission
        MallPermission mpQ = new MallPermission();
        mpQ.setAvailable("Y");
        List<MallPermission> mpList = mallPermissionService.getList(mpQ);
        for(MallRole mallRole: mallRoleList) {
            MallRolePermission qRP = new MallRolePermission();
            qRP.setRoleId(mallRole.getId());
            List<MallRolePermission> mallRolePermissionList = mallRolePermissionService.getList(qRP);
            if (mpList.size() != mallRolePermissionList.size()) {
                // 3. permission不一致, 添加到mall_role_permission
                for(MallPermission mp: mpList) {
                    if (mallRolePermissionList.stream().anyMatch(mallRolePermission -> mp.getId().equals(mallRolePermission.getPermissionId())))
                        continue;
                    // 3.1 添加到mall_role_permission
                    try {
                        mallRolePermissionService.saveOrUpdate(new MallRolePermission(){{
                            setTenantId(mallRole.getTenantId());
                            setPermissionId(mp.getId());
                            setRoleId(mallRole.getId());
                        }});
                    } catch (Exception e) {
                        logger.error(e.getMessage());
                    }
                }
            }
        }
    }

    @ApiOperation("用户菜单迁移")
    @GetMapping("/moveMenus")
    public ResultData moveMenus() {
        logger.debug("[" + getIpAddr() + "] MallPermissionController::moveMenus");
        MallUserInfo userInfo = getUser();
        if(userInfo.isFmSuperAdmin()) {
            // 1. 账号->系统
            moveAccountToSys();
            // 2. 合同添加商铺+多经点位
            addMenusForContract();
            // 3. 账单
            addMenusForBills();
            return new ResultData();
        }
        return new ResultData(ErrorCode.USER_NO_PERMISSION);
    }



    private void moveAccountToSys() {
        Long menuId_XiTong = 50L;
        Long menuId_Account = 7L;
        // 1. 修改菜单名
        mallMenuMapper.updateMallPermission(new MallPermission() {{
            setName("系统设置");
            setId(menuId_XiTong);
        }});
        // 2. 迁移->系统设置
        MallPermission accountPermission = mallPermissionService.getById(menuId_Account);
        mallMenuMapper.updatePermissionByParentId(new MallPermission() {{
            setParentId(menuId_XiTong);
            setOrigParentId(menuId_Account);
        }});
        // 3. 角色是否选中系统设置
        List<MallRolePermission> mallRolePermissions = mallRolePermissionService.getList(new MallRolePermission(){{
            setPermissionId(menuId_Account);
        }});
        for(MallRolePermission mallRolePermission: mallRolePermissions) {
            List<MallRolePermission> mallRolePermissionList = mallRolePermissionService.getList(new MallRolePermission(){{
                setTenantId(mallRolePermission.getTenantId());
                setRoleId(mallRolePermission.getRoleId());
                setPermissionId(menuId_XiTong);
            }});
            if (mallRolePermissionList.size() <= 0) {
                // update 7L->50L
                try {
                    mallRolePermissionService.saveOrUpdate(new MallRolePermission(){{
                        setTenantId(mallRolePermission.getTenantId());
                        setId(mallRolePermission.getId());
                        setPermissionId(menuId_XiTong);
                        setRoleId(mallRolePermission.getRoleId());
                    }});
                } catch (Exception e) {
                    logger.error(e.getMessage());
                }
            }
        }
        // 4. 删除permission/role
        mallMenuMapper.deletePermissionRole(new MallRolePermission(){{
            setPermissionId(menuId_Account);
        }});
        // 5. 删除permission
        mallPermissionService.deleteById(menuId_Account);
    }

    private void addMenusForContract() {

        Long menuId_Shop = 299L;
        Long menuId_Duojing = 300L;
        // 1. add new folder
        try {
            mallPermissionMapper.insert(new MallPermission() {{
                setId(menuId_Shop);
                setName("店铺");
                setParentId(3L);
                setAvailable("Y");
                setResourceType(0);
                setIcon("icon-iconshangpuguanli");
                setVersionType(0);
                setSort(menuId_Shop.intValue());
            }});
            mallPermissionMapper.insert(new MallPermission() {{
                setId(menuId_Duojing);
                setName("多经点位");
                setParentId(3L);
                setAvailable("Y");
                setResourceType(0);
                setIcon("icon-shanghuguanli");
                setVersionType(0);
                setSort(menuId_Duojing.intValue());
            }});
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
        // 2. move
        // 301, 302, 305
        mallMenuMapper.updatePermissionByParentId(new MallPermission() {{
            List<Long> list = new ArrayList<Long>();
            list.add(301L);
            list.add(302L);
            list.add(305L);
            setParentId(menuId_Shop);
            setIds(list);
        }});
        // 303, 304, 306
        mallMenuMapper.updatePermissionByParentId(new MallPermission() {{
            List<Long> list = new ArrayList<Long>();
            list.add(303L);
            list.add(304L);
            list.add(306L);
            setParentId(menuId_Duojing);
            setIds(list);
        }});
        mallMenuMapper.updateMallPermission(new MallPermission() {{
            setName("租金合同");
            setId(301L);
        }});
        mallMenuMapper.updateMallPermission(new MallPermission() {{
            setName("物业合同");
            setId(302L);
        }});
        mallMenuMapper.updateMallPermission(new MallPermission() {{
            setName("租金+物业合同");
            setId(305L);
        }});
        mallMenuMapper.updateMallPermission(new MallPermission() {{
            setName("租金合同");
            setId(303L);
        }});
        mallMenuMapper.updateMallPermission(new MallPermission() {{
            setName("物业合同");
            setId(304L);
        }});
        mallMenuMapper.updateMallPermission(new MallPermission() {{
            setName("租金+物业合同");
            setId(306L);
        }});
        // 3. 角色是否选中商铺
        List<MallRolePermission> mallRolePermissions = mallMenuMapper.getMallRolePermissions(new MallRolePermission(){{
            List<Long> list = new ArrayList<Long>();
            list.add(301L);
            list.add(302L);
            list.add(305L);
            setPermissionIds(list);
        }});
        for(MallRolePermission mallRolePermission: mallRolePermissions) {
            List<MallRolePermission> mallRolePermissionList = mallRolePermissionService.getList(new MallRolePermission(){{
                setTenantId(mallRolePermission.getTenantId());
                setRoleId(mallRolePermission.getRoleId());
                setPermissionId(menuId_Shop);
            }});
            if (mallRolePermissionList.size() <= 0) {
                try {
                    mallRolePermissionService.saveOrUpdate(new MallRolePermission(){{
                        setTenantId(mallRolePermission.getTenantId());
                        setPermissionId(menuId_Shop);
                        setRoleId(mallRolePermission.getRoleId());
                    }});
                } catch (Exception e) {
                    logger.error(e.getMessage());
                }
            }
        }
        // 4. 角色是否选中多经点位
        mallRolePermissions = mallRolePermissionService.getList(new MallRolePermission(){{
            List<Long> list = new ArrayList<Long>();
            list.add(303L);
            list.add(304L);
            list.add(306L);
            setPermissionIds(list);
        }});
        for(MallRolePermission mallRolePermission: mallRolePermissions) {
            List<MallRolePermission> mallRolePermissionList = mallRolePermissionService.getList(new MallRolePermission(){{
                setTenantId(mallRolePermission.getTenantId());
                setRoleId(mallRolePermission.getRoleId());
                setPermissionId(menuId_Duojing);
            }});
            if (mallRolePermissionList.size() <= 0) {
                try {
                    mallRolePermissionService.saveOrUpdate(new MallRolePermission(){{
                        setTenantId(mallRolePermission.getTenantId());
                        setPermissionId(menuId_Duojing);
                        setRoleId(mallRolePermission.getRoleId());
                    }});
                } catch (Exception e) {
                    logger.error(e.getMessage());
                }
            }
        }
    }

    private void addMenusForBills() {
        // 1. 账单列表隐藏
        mallPermissionService.saveOrUpdate(new MallPermission(){{
            setId(412L);
            setAvailable("N");
        }});
        addNewMunuFolder_ZhangdanList();
        addNewMenuFolder_Duizhang();
    }

    private void addNewMunuFolder_ZhangdanList() {
        // 1. 新增新的账单列表folder
        Long menuId_Zhangdanliebiao = 415L;
        try {
            mallPermissionMapper.insert(new MallPermission() {{
                setId(menuId_Zhangdanliebiao);
                setName("账单列表");
                setParentId(4L);
                setAvailable("Y");
                setResourceType(0);
                setIcon("icon-zhangdan5");
                setVersionType(0);
                setSort(menuId_Zhangdanliebiao.intValue());
            }});
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
        // 2. 迁移到账单列表下
        mallMenuMapper.updatePermissionByParentId(new MallPermission() {{
            List<Long> list = new ArrayList<Long>();
            list.add(402L);
            list.add(403L);
            list.add(404L);
            list.add(405L);
            list.add(406L);
            list.add(407L);
            list.add(408L);
            setParentId(menuId_Zhangdanliebiao);
            setIds(list);
        }});
        // 3. 角色是否选中账单列表
        List<MallRolePermission> mallRolePermissions = mallMenuMapper.getMallRolePermissions(new MallRolePermission(){{
            List<Long> list = new ArrayList<Long>();
            list.add(402L);
            list.add(403L);
            list.add(404L);
            list.add(405L);
            list.add(406L);
            list.add(407L);
            list.add(408L);
            setPermissionIds(list);
        }});
        for(MallRolePermission mallRolePermission: mallRolePermissions) {
            List<MallRolePermission> mallRolePermissionList = mallRolePermissionService.getList(new MallRolePermission(){{
                setTenantId(mallRolePermission.getTenantId());
                setRoleId(mallRolePermission.getRoleId());
                setPermissionId(menuId_Zhangdanliebiao);
            }});
            if (mallRolePermissionList.size() <= 0) {
                try {
                    mallRolePermissionService.saveOrUpdate(new MallRolePermission(){{
                        setTenantId(mallRolePermission.getTenantId());
                        setPermissionId(menuId_Zhangdanliebiao);
                        setRoleId(mallRolePermission.getRoleId());
                    }});
                } catch (Exception e) {
                    logger.error(e.getMessage());
                }
            }
        }
    }

    private void addNewMenuFolder_Duizhang() {
        // 1. 新增对账管理
        Long menuId_ZhangdanMan = 416L;
        try {
            mallPermissionMapper.insert(new MallPermission() {{
                setId(menuId_ZhangdanMan);
                setName("对账管理");
                setParentId(4L);
                setAvailable("Y");
                setResourceType(0);
                setIcon("icon-zhangdan11");
                setVersionType(0);
                setSort(menuId_ZhangdanMan.intValue());
            }});
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
        // 2. 迁移到对账管理下
        mallMenuMapper.updatePermissionByParentId(new MallPermission() {{
            List<Long> list = new ArrayList<Long>();
            list.add(409L);
            list.add(410L);
            list.add(411L);
            setParentId(menuId_ZhangdanMan);
            setIds(list);
        }});
        // 3. 角色是否选中对账管理
        List<MallRolePermission> mallRolePermissions = mallMenuMapper.getMallRolePermissions(new MallRolePermission(){{
            List<Long> list = new ArrayList<Long>();
            list.add(409L);
            list.add(410L);
            list.add(411L);
            setPermissionIds(list);
        }});
        for(MallRolePermission mallRolePermission: mallRolePermissions) {
            List<MallRolePermission> mallRolePermissionList = mallRolePermissionService.getList(new MallRolePermission(){{
                setTenantId(mallRolePermission.getTenantId());
                setRoleId(mallRolePermission.getRoleId());
                setPermissionId(menuId_ZhangdanMan);
            }});
            if (mallRolePermissionList.size() <= 0) {
                try {
                    mallRolePermissionService.saveOrUpdate(new MallRolePermission(){{
                        setTenantId(mallRolePermission.getTenantId());
                        setPermissionId(menuId_ZhangdanMan);
                        setRoleId(mallRolePermission.getRoleId());
                    }});
                } catch (Exception e) {
                    logger.error(e.getMessage());
                }
            }
        }
    }

    @Autowired
    private RequestMappingHandlerMapping requestMappingHandlerMapping;

    @ApiOperation("导出菜单")
    @GetMapping("/export")
    //@RequiresPermissions("sys:menu:import")
    @SystemControllerLog(description = "用户管理-导出权限")
    public ResultData export() {
        logger.debug("[" + getIpAddr() + "] MallPermissionController::export");
        List<Map> resourceList = new ArrayList<Map>();
        //获取所有Controller的方法
        Map<RequestMappingInfo, HandlerMethod> map = requestMappingHandlerMapping.getHandlerMethods();
        for (Map.Entry<RequestMappingInfo, HandlerMethod> m : map.entrySet()) {
            RequestMappingInfo info = m.getKey();
            HandlerMethod method = m.getValue();
            PatternsRequestCondition p = info.getPatternsCondition();
            //扫描Shiro的权限资源标签
            RequiresPermissions requiresPermissions = method.getMethod().getAnnotation(RequiresPermissions.class);
            if (requiresPermissions != null) {
                Map newSource = new HashMap();
                String[] strArr = requiresPermissions.value();
                newSource.put("permission", strArr[0]);
                //扫描Swagger注解
                ApiOperation apiOperation = method.getMethod().getAnnotation(ApiOperation.class);
                if (apiOperation != null) {
                    newSource.put("name", apiOperation.value());
                    Set<String> urls = p.getPatterns();
                    newSource.put("url", urls.toArray()[0]);
                }
                resourceList.add(newSource);
            }
        }

        return new ResultData(resourceList);
    }

    /**
     * 验证参数是否正确
     */
    private void verifyForm(MallPermission menu){
        if(StringUtils.isBlank(menu.getName())){
            throw new MallinkException(ErrorCode.MENU_NAME_EMPTY);
        }

        if(menu.getParentId() == null){
            throw new MallinkException(ErrorCode.MENU_PARENT_EMPTY);
        }

        //菜单
        if(menu.getResourceType().equals(EnumPermissionType.MENU.getCode())){
            if(StringUtils.isBlank(menu.getUrl())){
                throw new MallinkException(ErrorCode.MENU_URL_EMPTY);
            }
        }

        //上级菜单类型
        int parentType = EnumPermissionType.CATALOG.getCode();
        if(menu.getParentId() != 0){
            MallPermission parentMenu = mallPermissionService.getById(menu.getParentId());
            parentType = parentMenu.getResourceType();
        }

        //目录、菜单
        if(menu.getResourceType().equals(EnumPermissionType.CATALOG.getCode()) ||
                menu.getResourceType().equals(EnumPermissionType.MENU.getCode())){
            if(parentType != EnumPermissionType.CATALOG.getCode()){
                throw new MallinkException(ErrorCode.MENU_PARENT_NOT_CATEGORY);
            }
            return ;
        }

        //按钮
        if(menu.getResourceType().equals(EnumPermissionType.BUTTON.getCode())){
            if(parentType != EnumPermissionType.MENU.getCode()){
                throw new MallinkException(ErrorCode.MENU_PARENT_NOT_MENU);
            }
            return ;
        }
    }


}
