package cn.ibizlab.uaaapi.rest.extensions;

import cn.ibizlab.core.uaa.domain.SYS_PERMISSION;
import cn.ibizlab.core.uaa.domain.SYS_PSAPPMENUITEM;
import cn.ibizlab.core.uaa.domain.SYS_PSDEOPPRIV;
import cn.ibizlab.core.uaa.service.ISYS_PERMISSIONService;
import cn.ibizlab.core.uaa.service.ISYS_PSAPPMENUITEMService;
import cn.ibizlab.core.uaa.service.ISYS_PSDEOPPRIVService;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.JsonNode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotBlank;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 为业务系统提供权限相关服务
 * 提供以下能力：
 * （1）返回用户权限数据（含菜单、表格、表单）
 * （2）业务系统权限数据初始化（含菜单、数据能力）：保存业务系统权限数据到UAA中，用于权限树展示
 */
@RestController
public class PermissionFeignService {


    @Autowired
    private ISYS_PERMISSIONService permissionService;

    @Autowired
    private ISYS_PSAPPMENUITEMService psappmenuitemService;

    @Autowired
    private ISYS_PSDEOPPRIVService psdeopprivService;

    /**
     * 根据登录的用户userid，系统标识，获取指定该系统下角色的菜单、或权限
     * @return
     */
    @GetMapping(value = "/uaa/permission/{userid}")
    public JSONObject getUserPermissionData(@Validated @NotBlank(message = "userid不允许为空")@PathVariable("userid") String userid, @Validated @NotBlank(message = "systemid不允许为空") @RequestParam("systemid") String systemid) {

        String menuSQL="SELECT\n" +
                "\tt3.PERMISSIONID as permissionid\n" +
                "FROM\n" +
                "\tibzrole_permission t\n" +
                "INNER JOIN ibzpermission t2 on t.SYS_PERMISSIONID = t2.SYS_PERMISSIONID\n" +
                "INNER JOIN ibzpsappmenuitem t3 on t2.SYS_PERMISSIONID=t3.SYS_PSAPPMENUITEMID\n" +
                "WHERE\n" +
                "t.SYS_ROLEID IN (\n" +
                " SELECT  SYS_ROLEID\n" +
                " FROM\n" +
                " IBZUSER_ROLE\n" +
                " WHERE\n" +
                " SYS_USERID = '%s'\n" +
                " )\n" +
                "AND t2.SYSTEMID = '%s'\n" +
                "AND t2.ENABLE = 1\n" +
                "AND t2.TYPE = 0";

        List<JSONObject> permissionList= permissionService.select(String.format(menuSQL,userid,systemid));   //查询用户权限下的菜单数据

        JSONObject permissionObj=new JSONObject();
        JSONObject gridData=new JSONObject();
        JSONObject formdata=new JSONObject();

        JSONArray menuArray=new JSONArray();//菜单
        if(permissionList.size()>0){
            for(Map permission :permissionList){
                if(!StringUtils.isEmpty(permission.get("permissionid"))){
                    menuArray.add(permission.get("permissionid"));
                }
            }
        }

        String opprivSQL="SELECT\n" +
                "\tT2.pssysmoduleid as sysmodule,\n" +
                "\tT2.psdataentityid as dataentity,\n" +
                "\tT2.psdedatasetid as dedataset,\n" +
                "\tT2.psdedatarangeid as dedatarange,\n" +
                "\tT1.sys_permissionname\n" +
                "FROM\n" +
                "\tibzrole_permission T\n" +
                "INNER JOIN ibzpermission T1 ON T.SYS_PERMISSIONID = T1.SYS_PERMISSIONID\n" +
                "INNER JOIN ibzpsdeoppriv T2 on T1.SYS_PERMISSIONID=t2.SYS_PSDEOPPRIVID\n" +
                "WHERE\n" +
                "\tT.SYS_ROLEID IN (\n" +
                "\t\tSELECT\n" +
                "\t\t\tSYS_ROLEID\n" +
                "\t\tFROM\n" +
                "\t\t\tIBZUSER_ROLE\n" +
                "\t\tWHERE\n" +
                "\t\t\tSYS_USERID = '%s'\n" +
                "\t)\n" +
                "AND T1.SYSTEMID = '%s'\n" +
                "AND T1.TYPE = 1";

        List<JSONObject> permissionList2= permissionService.select(String.format(opprivSQL,userid,systemid));   //查询用户权限下的菜单数据

        gridData=getGridPermission(permissionList2);//拿到表格需要json数据
        formdata=getFormPermission(permissionList2);

        permissionObj.put("menuList",menuArray);
        permissionObj.put("dataAbility-grid",gridData);
        permissionObj.put("dataAbility-form",formdata);

        return permissionObj;
    }

    private JSONObject getGridPermission(List<JSONObject> role_permissions){

        JSONObject permission_entity= new JSONObject(); //顶级模块数据,表格
        for(Map rolePermission:role_permissions){
            JSONObject obj = JSONObject.parseObject(JSONObject.toJSON(rolePermission).toString());
            String str_entity=obj.getString("dataentity");
            String str_dataset=obj.getString("dedataset");
            String str_datarange=obj.getString("dedatarange");
            String str_permissionname=obj.getString("sys_permissionname");

            JSONObject cur_entity=new JSONObject();
            JSONObject cur_dataset=new JSONObject();
            JSONArray cur_permission=new JSONArray();

            if(permission_entity.containsKey(str_entity))
                cur_entity=permission_entity.getJSONObject(str_entity);

            if(cur_entity.containsKey(str_dataset))//数据集合并
                cur_dataset=cur_entity.getJSONObject(str_dataset);

            if(cur_dataset.containsKey(str_permissionname))//数据能力合并
                cur_permission=cur_dataset.getJSONArray(str_permissionname);

            cur_permission.add(str_datarange);

            cur_dataset.put(str_permissionname,cur_permission);

            cur_entity.put(str_dataset,cur_dataset);

            permission_entity.put(str_entity,cur_entity);
        }
        return permission_entity;
    }

    //表单数据拼接
    private JSONObject getFormPermission(List<JSONObject> role_permissions) {

        JSONObject permission_entity= new JSONObject();
        for (Map rolePermission : role_permissions) {
            JSONObject obj = JSONObject.parseObject(JSONObject.toJSON(rolePermission).toString());
            String str_entity = obj.getString("dataentity");
            String str_datarange = obj.getString("dedatarange");
            String str_permissionname = obj.getString("sys_permissionname");

            JSONObject cur_entity = new JSONObject();
            JSONObject cur_dataset = new JSONObject();
            JSONArray cur_permission = new JSONArray();


            if (permission_entity.containsKey(str_entity))//实体合并
                cur_entity = permission_entity.getJSONObject(str_entity);

            if (cur_entity.containsKey(str_permissionname))//数据能力合并
                cur_permission = cur_entity.getJSONArray(str_permissionname);

            cur_permission.add(str_datarange);

            cur_dataset.put(str_permissionname, cur_permission);

            cur_entity.put(str_permissionname, cur_permission);

            permission_entity.put(str_entity, cur_entity);
        }
        return permission_entity;
    }


    /**
     * 拿到业务系统传过来的权限和菜单数据，存入uaa的权限表中
     */
    @PostMapping("/uaa/permission/save")
    public Map<String, JsonNode> pushSystemPermissionData(@RequestBody Map<String,Object> map, @Validated @NotBlank(message = "systemid不允许为空")@RequestParam("systemid")String systemId){
        //如果map值不为null说明要更新数据，则先将表中该系统标识下的所有数据进行逻辑删除
        if(map!=null){
            permissionService.execute(String.format("UPDATE ibzpermission  t SET t.enable=0  WHERE SYSTEMID='%s'",systemId));
        }
        List<SYS_PSAPPMENUITEM> menuItemList=new ArrayList<>();//操作能力集合
        List<SYS_PSDEOPPRIV> opprivList=new ArrayList<>();//菜单项集合
        List<SYS_PERMISSION> ability_list=new ArrayList<>();//资源-操作能力集合
        List<SYS_PERMISSION> menu_list=new ArrayList<>();//资源-菜单项集合
        if(map.containsKey("permission")){
            JSONObject paramsObj = new JSONObject(map);
            JSONArray capabilityPermissionObj = paramsObj.getJSONArray("permission");
            parseDECapability(capabilityPermissionObj,systemId,ability_list,opprivList);
        }
        if (map.containsKey("menu")){
            JSONObject paramsObj = new JSONObject(map);
            JSONArray menuList = paramsObj.getJSONArray("menu");
            for(int a=0;a<menuList.size();a++){
                JSONObject menuPermissionObj = menuList.getJSONObject(a);
                if(menuPermissionObj.containsKey("items")){
                    String app_id=menuPermissionObj.getString("appid"); //应用名称
                    String app_name=menuPermissionObj.getString("appname"); //应用名称
                    String menu_name=menuPermissionObj.getString("name");  //菜单名称
                    String menu_logicName=menuPermissionObj.getString("logicname");  //菜单名称
                    parseMenu(menuPermissionObj.getJSONArray("items"),"",app_name,menu_name,systemId,menu_list,menuItemList,app_id,menu_logicName);
                }
            }
        }
        if(menuItemList.size()>0){
            psappmenuitemService.saveOrUpdateBatch(menuItemList);//批量保存菜单项
        }
        if(opprivList.size()>0){
            psdeopprivService.saveOrUpdateBatch(opprivList);//批量保存数据操作标识
        }
        if(menu_list.size()>0){
            permissionService.saveOrUpdateBatch(menu_list);//批量保存菜单项资源
        }
        if(ability_list.size()>0){
            permissionService.saveOrUpdateBatch(ability_list);//批量保存数据操作标识资源
        }
        return null;
    }

    /**
     * 递归解析菜单数据
     * @param childNodeArr   菜单项集合
     * @param p_permissionid  菜单项父标识
     * @param app_name  前端应用
     * @param menu_name  菜单
     */
    public void parseMenu(JSONArray childNodeArr, String p_permissionid, String app_name, String menu_name, String systemid, List<SYS_PERMISSION> menu_list , List<SYS_PSAPPMENUITEM> menuItemList, String app_id, String menu_logicName){
        int isLeaf=0;
        for(int a=0;a<childNodeArr.size();a++){
            JSONObject childNode=childNodeArr.getJSONObject(a);
            String menu_id=childNode.getString("id");
            if(childNode.containsKey("items")){
                JSONArray nodeArr=childNode.getJSONArray("items");
                parseMenu(nodeArr,menu_id,app_name,menu_name,systemid,menu_list,menuItemList,app_id,menu_logicName);
                if(nodeArr.size()>0)//判断当前菜单为叶子节点
                  isLeaf=1;
            }
            saveMenuPermission(childNode,p_permissionid,app_name,menu_name,systemid,isLeaf,menu_list,menuItemList,menu_id,app_id,menu_logicName);//保存菜单数据
        }
    }


    /**
     * 保存菜单数据
     * @param menuObj  菜单项
     * @param p_permissionid  菜单项父标识
     * @param app_name  前端应用
     * @param menu_name  菜单
 *     @param isLeaf 判断当前菜单为叶子节点
     */
    private void saveMenuPermission(JSONObject menuObj, String p_permissionid, String app_name, String menu_name, String systemid, int isLeaf, List<SYS_PERMISSION> menu_list, List<SYS_PSAPPMENUITEM> menuItemList , String menu_id, String app_id, String menu_logicName){


        String sysPermissionId= DigestUtils.md5DigestAsHex(String.format("%s%s",systemid,menu_id).getBytes());

        //存资源表
        SYS_PERMISSION sys_permission =new SYS_PERMISSION();
        sys_permission.setPermissionname(menuObj.getString("text"));
        sys_permission.setPssystemid(systemid);
        sys_permission.setPermissionid(sysPermissionId);
        sys_permission.setType("0");
        sys_permission.setEnable(1);
        menu_list.add(sys_permission);

        //存菜单项表
        SYS_PSAPPMENUITEM psAppMenuItem=new SYS_PSAPPMENUITEM();
        psAppMenuItem.setAppmenuitemid(sysPermissionId);
        psAppMenuItem.setAppmenuitemname(menuObj.getString("text"));
        psAppMenuItem.setPsappid(app_id);
        psAppMenuItem.setPsappname(app_name);
        psAppMenuItem.setPsappmenuid(menu_name);
        psAppMenuItem.setPsappmenuname(menu_logicName);
        psAppMenuItem.setPssystemid(systemid);
        psAppMenuItem.setPermissionid(menu_id);
        psAppMenuItem.setParentpermissionid(p_permissionid);
        psAppMenuItem.setIsleaf(isLeaf);
        menuItemList.add(psAppMenuItem);
    }

    /**
     * 递归解析实体数据能力
     * @param childNodeArr
     * @param
     */
    public void parseDECapability(JSONArray childNodeArr, String systemid, List<SYS_PERMISSION> ability_list, List<SYS_PSDEOPPRIV> opprivList){

        for(int a=0;a<childNodeArr.size();a++){

            JSONObject childNode=childNodeArr.getJSONObject(a);

            String deName=childNode.getString("dename");   //实体逻辑名
            String delogicname=childNode.getString("delogicname");   //实体逻辑名
            JSONObject sysmoudle=childNode.getJSONObject("sysmoudle");     //系统模块

            JSONArray dedataset=childNode.getJSONArray("dedataset");
            JSONArray dedatarange=childNode.getJSONArray("dedatarange");
            JSONArray deprivs=childNode.getJSONArray("deprivs");

            for(int b=0;b<dedataset.size();b++){
                JSONObject dataset_name= dedataset.getJSONObject(b);
                for(int c=0;c<dedatarange.size();c++){
                    JSONObject datarange_name= dedatarange.getJSONObject(c);
                    for(int d=0;d<deprivs.size();d++){
                        JSONObject deprivs_name= deprivs.getJSONObject(d);
                        saveDECapability(sysmoudle,deName,delogicname,dataset_name,datarange_name,deprivs_name,systemid,ability_list,opprivList);
                    }
                }
            }
        }
    }

    /**
     * 保存实体数据能力
     * @param sysmoudle  系统模块
     * @param delogicname  实体
     * @param dataset_name  实体数据集
     * @param datarange_name  实体数据范围
     * @param deprivs_name  实体操作能力
     */
    private void saveDECapability(JSONObject sysmoudle, String deName , String delogicname, JSONObject dataset_name, JSONObject datarange_name, JSONObject deprivs_name, String systemid, List<SYS_PERMISSION> ability_list, List<SYS_PSDEOPPRIV> opprivList) {

        String permissionId= DigestUtils.md5DigestAsHex(String.format("%s%s%s%s%s%s",systemid,sysmoudle,delogicname,dataset_name,datarange_name,deprivs_name).getBytes());
        String sysPermissionId= DigestUtils.md5DigestAsHex(String.format("%s%s",systemid,permissionId).getBytes());

        //存资源表
        SYS_PERMISSION sys_permission =new SYS_PERMISSION();
        sys_permission.setPermissionname(deprivs_name.getString("name"));
        sys_permission.setPssystemid(systemid);
        sys_permission.setPermissionid(sysPermissionId);
        sys_permission.setType("1");
        sys_permission.setEnable(1);
        ability_list.add(sys_permission);

        //存数据操作能力表
        SYS_PSDEOPPRIV psDEOppriv=new SYS_PSDEOPPRIV();
        psDEOppriv.setPsdeopprivid(sysPermissionId);
        psDEOppriv.setPsdeopprivname(deprivs_name.getString("name"));
        psDEOppriv.setPermissionid(permissionId);
        psDEOppriv.setPssystemid(systemid);
        psDEOppriv.setPssysmoduleid(sysmoudle.getString("id"));
        psDEOppriv.setPssysmodulename(sysmoudle.getString("name"));
        psDEOppriv.setPsdataentityid(deName);
        psDEOppriv.setPsdataentityname(delogicname);
        psDEOppriv.setPsdedatasetid(dataset_name.getString("id"));
        psDEOppriv.setPsdedatasetname(dataset_name.getString("name"));
        psDEOppriv.setPsdedatarangeid(datarange_name.getString("id"));
        psDEOppriv.setPsdedatarangename(datarange_name.getString("name"));
        opprivList.add(psDEOppriv);
    }
}
