package com.boman.web.core.utils;

import com.alibaba.fastjson.JSONObject;
import com.boman.domain.constant.CacheConstants;
import com.boman.common.core.utils.SecurityUtils;
import com.boman.common.core.utils.SpringUtils;
import com.boman.common.redis.service.RedisService;
import com.boman.domain.GenTable;
import com.boman.domain.SysRoleData;
import com.boman.domain.constant.FormDataConstant;
import com.boman.domain.constant.GlobalBtn;
import com.boman.domain.exception.NoSuchFunctionException;
import com.boman.system.api.RemoteMenuService;
import com.boman.system.api.RemoteRoleDataService;
import com.boman.domain.SysMenu;
import com.boman.domain.SysRole;
import com.boman.domain.SysUser;
import com.boman.system.api.model.LoginUser;
import com.boman.domain.dto.FormDataDto;
import com.boman.web.core.service.common.ICommonService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

import static com.boman.common.core.utils.obj.ObjectUtils.*;
import static com.boman.web.core.utils.ColumnUtils.joinList;
import static com.boman.web.core.utils.ColumnUtils.joinList1;

/**
 * @author shiqian
 * @date 2021年04月27日 10:48
 **/
public class AuthUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger(AuthUtils.class);

    public static boolean checkAuthObjectDelete(GenTable genTable, Long id, String pkName) {
        String functionName = genTable.getFunctionName();
        if (!containsFunctionBool(genTable.getMenuRole(), GlobalBtn.D, functionName)) {
            return false;
        }

        String tableName = genTable.getTableName();
        LoginUser loginUser = getLoginUser();
        if (SysUser.isAdmin(loginUser.getUserid())) {
            return true;
        }

        if (!checkPermsAuthBool(tableName, GlobalBtn.D)) {
            return false;
        }

        return checkRoleDataAuthBool(tableName, pkName, id);
    }

    public static void checkAuthQueryList(GenTable genTable, JSONObject condition) {
        containsFunction(genTable.getMenuRole(), GlobalBtn.Q, "此模块:[" + genTable.getFunctionName() + "], 没有查询功能");

        LoginUser loginUser = getLoginUser();
        if (SysUser.isAdmin(loginUser.getUserid())) {
            return;
        }

        List<Long> roleIdList = map(loginUser.getSysUser().getRoles(), SysRole::getId);
        RemoteRoleDataService remoteRoleDataService = SpringUtils.getBean(RemoteRoleDataService.class);
        List<SysRoleData> roleDataList = remoteRoleDataService.listByRoleIdList(roleIdList);
        if (isEmpty(roleDataList)) {
            return;
        }
        // 此张表所对应的roleData
        SysRoleData roleData = filterOne(roleDataList, sysRoleData -> genTable.getTableName().equals(sysRoleData.getTableName()));
        packAuthCondition(roleData.getDataScope(), condition, loginUser);
    }

    public static boolean checkAuthGetObject(GenTable genTable, Long id) {
        return checkAuthObjectDelete(genTable, id, IdUtils.getPkName(genTable.getColumns()));
    }

    /**
     * 功能描述: 某一张表是否有AMD....功能
     *
     * @param menuRole  AMDQSUE
     * @param funcType  AMDQSUE中的其中一个
     * @param errMsg    错误提示语
     */
    public static void containsFunction(String menuRole, String funcType, String errMsg) {
        if (isEmpty(menuRole)) {
            throw new NoSuchFunctionException("菜单权限未配置");

        }
        if (!menuRole.contains(funcType)) {
            throw new NoSuchFunctionException(errMsg);
        }
    }
    /**
     * 功能描述: 某一张表是否有AMD....功能
     *
     * @param menuRole  AMDQSUE
     * @param funcType  AMDQSUE中的其中一个
     */
    public static boolean containsFunctionBool(String menuRole, String funcType, String functionName) {
        if (!menuRole.contains(funcType)) {
            LOGGER.error("非法操作，操作人: {}，模块: {}, 此模块无 {} 功能", getLoginUser().getUsername(), functionName, funcType(funcType));
            return false;
        }

        return true;
    }

    /**
     * 功能描述: 拿到当前登陆人
     */
    public static LoginUser getLoginUser() {
        RedisService redisService = SpringUtils.getBean(RedisService.class);
        return redisService.getCacheObject(CacheConstants.LOGIN_TOKEN_KEY + SecurityUtils.getToken());
    }

    /**
     * 功能描述: 封装表的perms   eg: sys_user:A sys_user:M sys_user:D
     *
     * @param tableName tableName
     * @param btnType   AMDQSUE
     * @return java.lang.String
     */
    public static String packPermsKey(String tableName, String btnType) {
        return tableName + ":" + btnType.toUpperCase();
    }

    /**
     * 功能描述: 当前登陆人对应的角色idList
     *
     * @return java.lang.Long
     */
    public static List<Long> getLoginUserRoleIdList() {
        List<SysRole> roles = getLoginUser().getSysUser().getRoles();
        return map(roles, SysRole::getId);
    }


    /**
     * 功能描述: 当前登陆人对应的角色idList
     *
     * @return java.lang.Long
     */
    public static List<String> getLoginUserPermsList() {
        RemoteMenuService remoteMenuService = SpringUtils.getBean(RemoteMenuService.class);
        List<SysMenu> menus = remoteMenuService.listMenusByUserId(getLoginUser().getUserid());
        return map(menus, SysMenu::getPerms);
    }

    /**
     * 功能描述: loginUser对应的Perms，权限认定
     *
     * @param tableName tableName
     * @param funcType    AMDQSUEI {@link GenTable}
     */
    public static void checkPermsAuth(String tableName, String funcType) {
        List<String> permsList = getLoginUserPermsList();
        String perms = packPermsKey(tableName, funcType);
        if (!permsList.contains(perms)) {
            LOGGER.error("非法操作，操作人: {}，tableName: {}， 操作类型: {}", getLoginUser().getUsername(), tableName, funcType(funcType));
            throw new NoSuchFunctionException("不好意思，您无权限操作");
        }
    }

    /**
     * 功能描述: loginUser对应的Perms，权限认定
     *
     * @param tableName tableName
     * @param funcType    AMDQSUEI {@link GenTable}
     */
    public static boolean checkPermsAuthBool(String tableName, String funcType) {
        List<String> permsList = getLoginUserPermsList();
        String perms = packPermsKey(tableName, funcType);
        if (!permsList.contains(perms)) {
            LOGGER.error("非法操作，操作人: {}，tableName: {}， 操作类型: 此人未配置 {} 权限", getLoginUser().getUsername(), tableName, funcType(GlobalBtn.D));
           return false;
        }

        return true;
    }

    /**
     * 功能描述: loginUser对应的roleData，权限认定
     *
     * @param tableName tableName
     * @param pkName    pkName
     * @param id        id
     */
    public static void checkRoleDataAuth(String tableName, String pkName, Long id) {
        List<Long> roleIdList = getLoginUserRoleIdList();
        RemoteRoleDataService remoteRoleDataService = SpringUtils.getBean(RemoteRoleDataService.class);
        List<SysRoleData> roleDataList = remoteRoleDataService.listByRoleIdListTableName(joinList(roleIdList), tableName);
        if (isEmpty(roleDataList)) {
            //没有配，证明有此表的全部权限
            return;
        }
        String dataScope = roleDataList.get(0).getDataScope();
        // 不可以修改
        if (!countByCreteBy(dataScope, pkName, id, tableName)) {
            LOGGER.error("非法操作，操作人: {}，tableName: {}, id: {}", getLoginUser().getUsername(), tableName, id);
            throw new NoSuchFunctionException("不好意思，您无权限操作");
        }
    }

    /**
     * 功能描述: loginUser对应的roleData，权限认定
     *
     * @param tableName tableName
     * @param pkName    pkName
     * @param id        id
     */
    public static boolean checkRoleDataAuthBool(String tableName, String pkName, Long id) {
        List<Long> roleIdList = getLoginUserRoleIdList();
        RemoteRoleDataService remoteRoleDataService = SpringUtils.getBean(RemoteRoleDataService.class);
        List<SysRoleData> roleDataList = remoteRoleDataService.listByRoleIdListTableName(joinList1(roleIdList), tableName);
        if (isEmpty(roleDataList)) {
            //没有配，证明有此表的全部权限
            return true;
        }

        String dataScope = roleDataList.get(0).getDataScope();
        // 可以修改
        if (countByCreteBy(dataScope, pkName, id, tableName)) {
            return true;
        }

        LOGGER.error("非法操作，操作人: {}，tableName: {}, id: {}", getLoginUser().getUsername(), tableName, id);
        return false;
    }

    /**
     * 功能描述: 根据crete_by到数据库 count, 如果 >0 可以修改
     *
     * @param dataScope dataScope
     * @param pkName    pkName
     * @param id        id
     * @param tableName tableName
     * @return boolean
     */
    public static boolean countByCreteBy(String dataScope, String pkName, Long id, String tableName) {
        ICommonService commonService = SpringUtils.getBean(ICommonService.class);

        JSONObject condition = new JSONObject();
        condition.put(pkName, id);
        // 封装crete_by
        packAuthCondition(dataScope, condition, getLoginUser());

        FormDataDto dto = new FormDataDto();
        dto.setTable(tableName);
        dto.setFixedData(condition);

        int count = commonService.count(dto);
        // count > 0 证明此人可以看到这条记录，自然可以修改
        return count > 0;
    }

    /**
     * 功能描述: 封装create_by in () 到 condition中
     *
     * @param dataScope obj_test:A obj_test:M.....
     * @param condition condition
     * @param loginUser 当前登陆人所存的deptUserIds和subDeptUserIds
     */
    public static void packAuthCondition(String dataScope, JSONObject condition, LoginUser loginUser) {
        requireNonNull(dataScope, "dataScope is empty");

        switch (dataScope) {
            case SysRoleData.ALL_DATA:
                break;
            case SysRoleData.DIY_DATA:
                break;
            case SysRoleData.SELF_DEPT_DATA:
                // 本部门人员
                condition.put(FormDataConstant.CREATE_BY, loginUser.getDeptUserIds());
                break;
            case SysRoleData.SUB_DEPT_DATA:
                // 本部门以及子部门
                condition.put(FormDataConstant.CREATE_BY, loginUser.getSubDeptUserIds());
                break;
            case SysRoleData.MYSELF_DATA:
                // 自己的
                condition.put(FormDataConstant.CREATE_BY, loginUser.getUserid());
                break;
            default:
                break;
        }
    }

    public static String funcType(String funcType) {
        switch (funcType) {
            case GlobalBtn.A:
                return "新增";
            case GlobalBtn.M:
                return "修改";
            case GlobalBtn.D:
                return "删除";
            case GlobalBtn.Q:
                return "查询";
            case GlobalBtn.S:
                return "提交";
            case GlobalBtn.U:
                return "反提交";
            case GlobalBtn.E:
                return "导出";
            case GlobalBtn.I:
                return "导入";
            default:
                return "未知";
        }
    }


}
