package cn.ibizlab.util.security;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.ibizlab.util.domain.EntityBase;
import cn.ibizlab.util.filter.QueryWrapperContext;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * spring security 权限管理类
 * 重写权限控制方法
 */
@Component
public class AuthPermissionEvaluator implements PermissionEvaluator {

    @Value("${ibiz.enablePermissionValid:false}")
    boolean enablePermissionValid;  //是否开启权限校验

    /**
     * 表格权限检查 ：用于检查当前用户是否拥有表格数据的读取、删除权限
     *
     * @param authentication
     * @param obj_action     表格行为，如：[READ,DELETE]
     * @param grid_param     表格参数，如：当前表格所处实体(EntityName)、表格删除的数据主键(srfkeys)
     * @return true/false true则允许当前行为，false拒绝行为
     */
    @Override
    public boolean hasPermission(Authentication authentication, Object obj_action, Object grid_param) {

        if(AuthenticationUser.getAuthenticationUser().getSuperuser()==1  || !enablePermissionValid)
            return true;  //系统没开启权限、超级管理员 两种情况不进行权限检查

        try{
            String action = "";

            if (obj_action instanceof String)
                action = (String) obj_action;

            if (StringUtils.isEmpty(action))
                return false;

            JSONObject permissionList= AuthenticationUser.getAuthenticationUser().getPermisionList();//获取权限列表

            if(permissionList==null)
                return false;

            List param_list = (ArrayList) grid_param;

            if(obj_action.equals("DELETE")){    //表格删除权限校验
                Object srfkey =param_list.get(0);
                EntityBase cur_entity = (EntityBase) param_list.get(1);
                String entityName = cur_entity.getClass().getSimpleName();
                ServiceImpl service= SpringContextHolder.getBean(String.format("%s%s",getBeanName(entityName),"ServiceImpl"));//获取当前实体service
                JSONObject formDataAbility=permissionList.getJSONObject("dataAbility-form");//由于表格删除是不跟着dataSet走，所以此处走form获取权限
                Map<String,String> permissionField=getPermissionField(cur_entity);//获取系统预置属性列表
                String selectCond=generatePermissionSQLForm(formDataAbility,entityName,action,srfkey,permissionField);//拼接权限条件
                if(StringUtils.isEmpty(selectCond))
                    return false;
                QueryWrapper permissionCond=getPermissionCond(selectCond,permissionField);
                return testDataAccess(service,permissionCond);//执行权限检查
            }
            else{   //表格查询权限校验

                Object searchContext=param_list.get(0);
                String dataSet=String.valueOf(param_list.get(1));
                EntityBase cur_entity = (EntityBase) param_list.get(2);
                String entityName = cur_entity.getClass().getSimpleName();

                if(StringUtils.isEmpty(entityName)|| StringUtils.isEmpty(dataSet)|| StringUtils.isEmpty(action))
                    return false;

                JSONObject gridDataAbility=permissionList.getJSONObject("dataAbility-grid");//获取表格的权限数据
                Map<String,String> permissionField=getPermissionField(cur_entity);//获取系统预置属性列表
                String selectCond=generatePermissionSQLGrid(gridDataAbility,entityName,action,dataSet,permissionField,null);//拼接权限条件
                if(StringUtils.isEmpty(selectCond))
                    return false;
                filterDataAccess(searchContext,selectCond);//过滤出权限内的数据
            }
                return true;
        }catch (Exception e){
            throw new RuntimeException("系统在进行权限检查时出现异常，原因为:"+e);
        }
    }

    /**
     * 表单权限检查 ：用于检查当前用户是否拥有表单的新建、编辑、删除权限
     *
     * @param authentication
     * @param srfkey         当前操作数据的主键
     * @param action         当前操作行为：如：[READ、UPDATE、DELETE]
     * @param cur_entity     当前操作的实体对象
     * @return true/false true则允许当前行为，false拒绝行为
     */
    @Override
    public boolean hasPermission(Authentication authentication, Serializable srfkey, String action, Object cur_entity) {

        if(AuthenticationUser.getAuthenticationUser().getSuperuser()==1  || !enablePermissionValid)
            return true;  //系统没开启权限、超级管理员 两种情况不进行权限检查

        boolean isPermission;

        EntityBase entityBase = null;

        if (cur_entity instanceof EntityBase)
            entityBase = (EntityBase) cur_entity;

        if (StringUtils.isEmpty(entityBase))
            return false;

        try {
            String entityName = entityBase.getClass().getSimpleName(); //实体名

            if(action.equals("CREATE")){  //表单新建权限校验
                JSONObject permissionList= AuthenticationUser.getAuthenticationUser().getPermisionList();//获取权限列表
                JSONObject formDataAbility=permissionList.getJSONObject("dataAbility-form");//获取表单的权限数据
                return isFormCreatePermission(formDataAbility,entityName,action);//拼接权限条件
            }
            else{ //表单编辑、查询权限校验
                ServiceImpl service= SpringContextHolder.getBean(String.format("%s%s",getBeanName(entityName),"ServiceImpl"));//获取当前实体service
                JSONObject permissionList= AuthenticationUser.getAuthenticationUser().getPermisionList();//获取权限列表
                JSONObject formDataAbility=permissionList.getJSONObject("dataAbility-form");//获取表单的权限数据
                Map<String,String> permissionField=getPermissionField(entityBase);
                String selectCond=generatePermissionSQLForm(formDataAbility,entityName,action,srfkey,permissionField);//拼接权限条件
                if(StringUtils.isEmpty(selectCond))
                    return false;
                QueryWrapper permissionCond=getPermissionCond(selectCond,permissionField);
                isPermission=testDataAccess(service,permissionCond);//执行权限检查
            }
        }catch (Exception e){
            throw new RuntimeException("系统在进行权限检查时出现异常，原因为:"+e);
        }
                return isPermission;
    }

    /**
     * 拼接表格查询条件
     * @param gridDataAbility
     * @param entityName
     * @param action
     * @param dataSet
     * @param permissionField
     * @param srfkey
     * @return
     */
    private String  generatePermissionSQLGrid(JSONObject gridDataAbility, String entityName, String action, String dataSet, Map<String,String> permissionField,Object srfkey){
        if(gridDataAbility==null)
            return null;
        if(!gridDataAbility.containsKey(entityName))
            return null;
        JSONObject entityObj=gridDataAbility.getJSONObject(entityName);//获取实体
        if(!entityObj.containsKey(dataSet))
            return null;
        JSONObject dedatasetObject=entityObj.getJSONObject(dataSet);//获取实体数据集
        if(!dedatasetObject.containsKey(action))
            return null;
        JSONArray entityOperation=dedatasetObject.getJSONArray(action);//行为：read；insert...
        if(entityOperation.size()==0)
            return null;

        if(StringUtils.isEmpty(srfkey))
            return getPermissionCond(entityOperation,permissionField); //拼接权限条件-查询
        else
            return String.format(" (%s) AND (%sid='%s')",getPermissionCond(entityOperation,permissionField),srfkey); //拼接权限条件-删除
    }


    /**
     * 表格拼接权限条件，过滤出权限数据
     * @param targetDomainObject
     * @param permissionCond
     * @throws Exception
     */
    private void filterDataAccess(Object targetDomainObject, String permissionCond) throws Exception{
        if(targetDomainObject instanceof QueryWrapperContext){
            QueryWrapperContext queryWrapperContext = (QueryWrapperContext) targetDomainObject;
            QueryWrapper queryWrapper = queryWrapperContext.getSelectCond();
            queryWrapper.apply(permissionCond);
        }
    }


    /**
     * 拼接表单数据查询条件
     * @param formDataAbility
     * @param entityName
     * @param action
     * @param srfkey
     * @param permissionField
     * @return
     */
    private String generatePermissionSQLForm(JSONObject formDataAbility, String entityName, String action, Object srfkey, Map<String,String> permissionField){
            if(formDataAbility==null)
                return null;
            if(!formDataAbility.containsKey(entityName))
                return null;
            JSONObject entityObj=formDataAbility.getJSONObject(entityName);//获取实体
            if(!entityObj.containsKey(action))
                return null;
            JSONArray entityOperation=entityObj.getJSONArray(action);//行为：read；insert...
            if(entityOperation.size()==0)
                return null;
            String resultCond=getPermissionCond(entityOperation,permissionField);
            if(StringUtils.isEmpty(srfkey))
                return String.format(" (%s)",resultCond,entityName.toLowerCase()); //拼接权限条件-新建
            else
                return String.format(" (%s) AND (%sid='%s')",resultCond,entityName.toLowerCase(),srfkey); //拼接权限条件-编辑
    }


    /**
     * 判断当前用户是否拥有建立表单数据权限
     * @param formDataAbility
     * @param entityName
     * @param targetType
     * @return
     */
    private boolean isFormCreatePermission(JSONObject formDataAbility, String entityName, String targetType){
        if(formDataAbility==null)
            return false;
        if(!formDataAbility.containsKey(entityName))
            return false;
        JSONObject entityObj=formDataAbility.getJSONObject(entityName);//获取实体
        if(!entityObj.containsKey(targetType))
            return false;
        return true;
    }

    /**
     * 表单权限检查
     * @param service
     * @param permissionCond
     * @return
     */
    private boolean testDataAccess(ServiceImpl service, QueryWrapper permissionCond){
         boolean isPermission=false;
             List list=service.list(permissionCond);
             if(list.size()>0)
                 isPermission=true;
        return isPermission;
    }


    /**
     * 拼接权限条件（表单/表格）共用
     * @param entityOperation
     * @param permissionField
     * @return
     */
    private String  getPermissionCond(JSONArray entityOperation, Map<String,String> permissionField){
        String orgField=permissionField.get("orgfield");
        String orgsecfield=permissionField.get("orgsecfield");
        StringBuffer cond=new StringBuffer();
        for(int i=0;i<entityOperation.size();i++){
            if(i>0 && (!StringUtils.isEmpty(cond.toString())))
                cond.append("OR");
            String permissionCond=entityOperation.getString(i);//权限配置条件
            if(permissionCond.equals("CUR_ORG")){   //本单位
                cond.append(String.format("(t1.%s='%s')",orgField,AuthenticationUser.getAuthenticationUser().getOrgid()));
            }
            if(permissionCond.equals("SUB_ORG")){//下级单位
                cond.append(" INSTR(j1.LEVELCODE,'"+AuthenticationUser.getAuthenticationUser().getLevelcode()+"')=1 ");
            }
            if(permissionCond.equals("HIT_ORG")){//上级单位
                cond.append(" INSTR('"+AuthenticationUser.getAuthenticationUser().getLevelcode()+"',j1.LEVELCODE)=1 ");
            }
            if(permissionCond.equals("CREATEMAN")){//建立人
                cond.append(String.format("(t1.createman='%s')",AuthenticationUser.getAuthenticationUser().getUserid()));
            }
//            if(permissionCond.equals("CUR_ORGSEC")){//本部门
//                cond.append(String.format("(t1.orgsecid='%s')",AuthenticationUser.getAuthenticationUser().getMdeptid()));
//            }
//            if(permissionCond.equals("SUB_ORGSEC")){//下级部门
//                cond.append(" INSTR(j2.LEVELCODE,'"+AuthenticationUser.getAuthenticationUser().getMdeptcode()+"')=1 ");
//            }
//            if(permissionCond.equals("HIGH_ORGSEC")){//上级部门
//                cond.append(" INSTR('"+AuthenticationUser.getAuthenticationUser().getMdeptcode()+"',j2.LEVELCODE)=1 ");
//            }
              if(permissionCond.equals("ALL")){//全部数据
                cond.append("(1=1)");
              }
        }
        if(StringUtils.isEmpty(cond.toString()))
            return "";

        String resultCond=cond.toString();
        if(resultCond.endsWith("OR")){
            resultCond=resultCond.substring(0,resultCond.lastIndexOf("OR"));
        }
        return  resultCond;
    }

    /**
     * 拼接权限查询条件(表单/表格)共用
     * @param whereCond
     * @param permissionField
     * @return
     */
    private QueryWrapper getPermissionCond(String whereCond, Map<String,String> permissionField){

        Wrapper  wrapper =new QueryWrapper();
        QueryWrapper allPermissionCond=new QueryWrapper();
        //permissionCond.apply("inner join JC_ORG j1 on t1.ORGID=j1.orgid inner join JC_ORGSEC j2 on t1.orgsecid=j2.orgsecid");

        if(StringUtils.isEmpty(whereCond))
            return allPermissionCond;

//        String strAllPermissionCond=String.format("inner join XT_ZZJG_DWBM j1 on t1.%s=j1.dwbm where (%s) ",permissionField.get("orgfield"),whereCond);

        allPermissionCond.apply(whereCond);

        return allPermissionCond;
    }

    /**
     * 获取实体权限字段 orgid/orgsecid
     * @param entityBase
     * @return
     */
    private Map<String,String> getPermissionField(EntityBase entityBase){
        Map<String,String> permissionFiled=new HashMap<>();
        String orgField="orgid";  //组织权限默认值
        String orgsecField="orgsecid"; //部门权限默认值
//        Map<Field, PreField> preFields= entityBase.SearchPreField(); //从缓存中获取当前类预置属性
//        //寻找实体权限属性
//        for (Map.Entry<Field,PreField> entry : preFields.entrySet()){
//            Field prefield=entry.getKey();//获取注解字段
//            PreField fieldAnnotation=entry.getValue();//获取注解值
//            PredefinedType prefieldType=fieldAnnotation.preType();
//            if(prefieldType==PredefinedType.ORGID)//用户配置系统预置属性-组织机构标识
//                orgField=prefield.getName();
//            if(prefieldType==PredefinedType.ORGSECTORID)//用户配置系统预置属性-部门标识
//                orgsecField=prefield.getName();
//        }
        permissionFiled.put("orgfield",orgField);
        permissionFiled.put("orgsecfield",orgsecField);
        return permissionFiled;
    }

    /**
     * 获取bean名称
     * @param className
     * @return
     */
    private  String getBeanName(String className) {
        if (Character.isLowerCase(className.charAt(0))) {
            return className;
        } else {
            return (new StringBuilder()).append(Character.toLowerCase(className.charAt(0))).append(className.substring(1)).toString();
        }
    }

}