package cn.ibizlab.api.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.domain.SYS_PSSYSUNIRES;
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 cn.ibizlab.core.uaa.service.ISYS_PSSYSUNIRESService;
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.sql.Timestamp;
import java.util.*;

/**
 * 为业务系统提供权限相关服务
 * 提供以下能力：
 * （1）返回用户权限数据（含菜单、表格、表单）
 * （2）业务系统权限数据初始化（含菜单、数据能力）：保存业务系统权限数据到UAA中，用于权限树展示
 */
@RestController
public class PermissionFeignService {
    /**
     * 实体操作标识
     */
    private String OPPriTag="OPPRIV";
    /**
     * 统一资源标识
     */
    private String UniResTag="UNIRES";
    /**
     * 菜单项标识
     */
    private String AppMenuTag="APPMENU";
    /**
     * 实体行为操作标识
     */
    private String DEActionType="DEACTION";
    /**
     * 实体数据集操作标识
     */
    private String DataSetTag="DATASET";

    @Autowired
    private ISYS_PERMISSIONService permissionService;

    @Autowired
    private ISYS_PSDEOPPRIVService opprivService;

    @Autowired
    private ISYS_PSSYSUNIRESService pssysuniresService;

    @Autowired
    private ISYS_PSAPPMENUITEMService psappmenuitemService;

    /**
     * 拿到业务系统传过来的权限和菜单数据，存入uaa的权限表中
     */
    @PostMapping("/uaa/permission/save")
    public JSONObject pushSystemPermissionData(@RequestBody Map<String,Object> map, @Validated @NotBlank(message = "systemid不允许为空")@RequestParam("systemid")String systemId){
        try {
            //如果map值不为null说明要更新数据，则先将表中该系统标识下的所有数据进行逻辑删除
            Map param=new HashMap();
            param.put("param0",systemId);
            String sql="UPDATE ibzpermission  t SET t.enable=0  WHERE SYSTEMID=#{et.param0} ";
            if(map!=null){
                permissionService.execute(sql,param);
            }
            List<SYS_PSDEOPPRIV> opprivList=new ArrayList<>();//数据能力
            List<SYS_PERMISSION> permission_list=new ArrayList<>();//资源
            List<SYS_PSSYSUNIRES> unires_list=new ArrayList<>();//统一资源
            List<SYS_PSAPPMENUITEM> menu_list=new ArrayList<>();//资源-菜单项集合
            if(map.containsKey("permission")){
                JSONObject paramsObj = new JSONObject(map);
                JSONObject capabilityPermissionObj = paramsObj.getJSONObject("permission");
                parseDECapability(capabilityPermissionObj,systemId,permission_list,opprivList);
                parseUniRes(capabilityPermissionObj,systemId,permission_list,unires_list);
                parseAppMenus(capabilityPermissionObj,systemId,permission_list,menu_list);
            }
            if(opprivList.size()>0){
                opprivService.saveOrUpdateBatch(opprivList);//批量保存数据能力
            }
            if(unires_list.size()>0){
                pssysuniresService.saveOrUpdateBatch(unires_list);//批量保存统一资源
            }
            if(menu_list.size()>0){
                psappmenuitemService.saveOrUpdateBatch(menu_list);//批量保存统一资源
            }
            if(permission_list.size()>0){
                permissionService.saveOrUpdateBatch(permission_list);//批量保存权限资源
            }
        } catch (Exception e) {
            return error("资源同步失败，失败原因为:"+e);
        }
        return success("资源同步成功");
    }

    /**
     * 存储菜单资源
     * @param capabilityPermissionObj
     * @param systemId
     * @param permission_list
     * @param menu_list
     */
    private void parseAppMenus(JSONObject capabilityPermissionObj, String systemId, List<SYS_PERMISSION> permission_list, List<SYS_PSAPPMENUITEM> menu_list) {
        if(capabilityPermissionObj!=null) {
            JSONArray appMenuArr = capabilityPermissionObj.getJSONArray("appmenus");
            if(appMenuArr.size()>0){
                for(int a=0;a<appMenuArr.size();a++){
                    JSONObject App=appMenuArr.getJSONObject(a);
                    String appId=App.getString("appid");
                    String appName=App.getString("appname");
                    if(App.containsKey("appmenu") && App.getJSONArray("appmenu").size()>0){
                        JSONArray AppMenuArr=App.getJSONArray("appmenu");
                        for(int b=0;b<AppMenuArr.size();b++){
                            JSONObject appMenu=AppMenuArr.getJSONObject(b);
                            String appMenuId=appMenu.getString("menuid");
                            String appMenuName=appMenu.getString("menuname");
                            if(appMenu.containsKey("menuitem")&& appMenu.getJSONArray("menuitem").size()>0){
                                JSONArray menuItemArr=appMenu.getJSONArray("menuitem");
                                parseMenuItems( menuItemArr , "", systemId, appId, appName, appMenuId, appMenuName, permission_list,  menu_list);
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 解析菜单项集合
     * @param menuItemArr
     * @param systemId
     * @param permission_list
     * @param menu_list
     */
    private void parseMenuItems(JSONArray menuItemArr ,String parentMenuItemId, String systemId, String appId, String appName, String appMenuId,String appMenuName, List<SYS_PERMISSION> permission_list, List<SYS_PSAPPMENUITEM> menu_list){
        for(int a=0;a<menuItemArr.size();a++){
            JSONObject menuItem=menuItemArr.getJSONObject(a);
            String menuItemId=menuItem.getString("id");
            String menuItemName=menuItem.getString("name");
            if(menuItem.containsKey("items") && menuItem.getJSONArray("items").size()>0){
                JSONArray tempMenuItems=menuItem.getJSONArray("items");
                parseMenuItems(tempMenuItems,menuItemId,systemId,appId,appName,appMenuId,appMenuName,permission_list,menu_list);
            }
            saveMenuItem(menuItemId,menuItemName,parentMenuItemId,systemId,appId,appName,appMenuId,appMenuName,permission_list,menu_list);
        }
    }

    /**
     * 保存菜单项
     * @param menuItemId
     * @param menuItemName
     * @param parentMenuItemId
     * @param systemId
     * @param appId
     * @param appName
     * @param appMenuId
     * @param appMenuName
     * @param permission_list
     * @param menu_list
     */
    private void saveMenuItem(String menuItemId,String menuItemName , String parentMenuItemId, String systemId, String appId, String appName, String appMenuId,String appMenuName, List<SYS_PERMISSION> permission_list, List<SYS_PSAPPMENUITEM> menu_list){

        String sysPermissionId=DigestUtils.md5DigestAsHex(String.format("%s%s%s%s",systemId,appId,appMenuId,menuItemId).getBytes());
        SYS_PERMISSION sys_permission =new SYS_PERMISSION();
        sys_permission.setPermissionid(sysPermissionId);
        sys_permission.setPermissionname(menuItemName);
        sys_permission.setPssystemid(systemId);
        sys_permission.setPermissiontype(AppMenuTag);
        sys_permission.setEnable(1);
        sys_permission.setCreatedate(new Timestamp(new Date().getTime()));
        sys_permission.setUpdatedate(new Timestamp(new Date().getTime()));
        permission_list.add(sys_permission);

        //存菜单项表
        SYS_PSAPPMENUITEM psAppMenuItem=new SYS_PSAPPMENUITEM();
        psAppMenuItem.setAppmenuitemid(sysPermissionId);
        psAppMenuItem.setAppmenuitemname(menuItemName);
        psAppMenuItem.setPsappid(appId);
        psAppMenuItem.setPsappname(appName);
        psAppMenuItem.setPsappmenuid(appMenuId);
        psAppMenuItem.setPsappmenuname(appMenuName);
        psAppMenuItem.setPssystemid(systemId);
        psAppMenuItem.setPsappmenuitemid(menuItemId);
        psAppMenuItem.setPsapppmenuitemid(parentMenuItemId);
        psAppMenuItem.setCreatedate(new Timestamp(new Date().getTime()));
        psAppMenuItem.setUpdatedate(new Timestamp(new Date().getTime()));
        menu_list.add(psAppMenuItem);
    }

    /**
     * 存储统一资源
     * @param capabilityPermissionObj
     */
    private void parseUniRes(JSONObject capabilityPermissionObj,String systemId,List<SYS_PERMISSION> permission_list,List<SYS_PSSYSUNIRES> unires_list) {
        if(capabilityPermissionObj!=null){
            JSONArray uniResArr=capabilityPermissionObj.getJSONArray("unires");
            if(uniResArr.size()>0){
                for(int a=0;a<uniResArr.size();a++){
                    JSONObject uniRes=uniResArr.getJSONObject(a);
                    createUniRes(uniRes,systemId,permission_list,unires_list);
                }
            }
        }
    }

    /**
     * 创建统一资源
     * @param uniRes
     */
    private void createUniRes(JSONObject uniRes ,String systemId,List<SYS_PERMISSION> permission_list,List<SYS_PSSYSUNIRES> unires_list) {

        String uniResCode=uniRes.getString("unirescode");
        String uniResName=uniRes.getString("uniresname");
        String uniResId= DigestUtils.md5DigestAsHex(String.format("%s%s",systemId,uniResCode).getBytes());

        SYS_PERMISSION sys_permission =new SYS_PERMISSION();
        sys_permission.setPermissionid(uniResId);
        sys_permission.setPermissionname(uniResName);
        sys_permission.setPssystemid(systemId);
        sys_permission.setPermissiontype(UniResTag);
        sys_permission.setEnable(1);
        sys_permission.setCreatedate(new Timestamp(new Date().getTime()));
        sys_permission.setUpdatedate(new Timestamp(new Date().getTime()));
        permission_list.add(sys_permission);

        SYS_PSSYSUNIRES sys_pssysunires=new SYS_PSSYSUNIRES();
        sys_pssysunires.setUniresid(uniResId);
        sys_pssysunires.setUniresname(uniResName);
        sys_pssysunires.setUnirescode(uniResCode);
        sys_pssysunires.setCreatedate(new Timestamp(new Date().getTime()));
        sys_pssysunires.setUpdatedate(new Timestamp(new Date().getTime()));
        unires_list.add(sys_pssysunires);
    }

    /**
     * 保存实体数据能力
     * @param permission
     * @param systemId
     * @param sysPermission
     * @param opprivPermission
     */
    public void parseDECapability(JSONObject permission, String systemId, List<SYS_PERMISSION> sysPermission, List<SYS_PSDEOPPRIV> opprivPermission){

        JSONArray preDefinedDataRange=permission.getJSONArray("predefineddatarange");
        JSONArray entities=permission.getJSONArray("entities");

        for(int a=0;a<entities.size();a++){
            JSONObject entity=entities.getJSONObject(a);
            JSONArray dataSetArray=entity.getJSONArray("dedataset");
            JSONArray deActionArray=entity.getJSONArray("deaction");
            createDataRange(dataSetArray,preDefinedDataRange,entity,DataSetTag,systemId,sysPermission,opprivPermission);//存储数据集
            createDataRange(deActionArray,preDefinedDataRange,entity,DEActionType,systemId,sysPermission,opprivPermission);//存储实体行为
        }
    }

    /**
     * 根据实体行为或数据集合结合预定于数据类型生成数据范围
     * @param deActionArray
     * @param preDefinedDataRange
     * @param entity
     * @param permissionType
     * @param systemId
     * @param ability_list
     * @param opprivList
     */
    private void createDataRange(JSONArray deActionArray , JSONArray preDefinedDataRange, JSONObject entity , String permissionType, String systemId , List<SYS_PERMISSION> ability_list, List<SYS_PSDEOPPRIV> opprivList){

        for(int b=0;b<deActionArray.size();b++) {
            JSONObject deSource = deActionArray.getJSONObject(b);
            String deActionType=deSource.getString("type");
            //数据查询与自定义行为不生成预置范围相关数据
            if( (permissionType.equalsIgnoreCase(DEActionType)  && !deActionType.equalsIgnoreCase("BUILTIN")) || (permissionType.equalsIgnoreCase(DataSetTag))   ) {
                JSONObject dataRange =new JSONObject();
                createDataRange(entity,deSource,dataRange,permissionType,systemId,ability_list,opprivList);
            }
            else{
                for(int c=0;c<preDefinedDataRange.size();c++){
                    JSONObject dataRange =preDefinedDataRange.getJSONObject(c);
                    createDataRange(entity,deSource,dataRange,permissionType,systemId,ability_list,opprivList);//实体预置行为及数据集
                }
            }
        }
    }

    /**
     * 根据实体行为或数据集合结合预定于数据类型生成数据范围
     * @param entity
     * @param source
     * @param dataRange
     * @param permissionType
     * @param systemId
     * @param ability_list
     * @param opprivList
     */
    private void createDataRange(JSONObject entity, JSONObject source , JSONObject dataRange, String permissionType, String systemId , List<SYS_PERMISSION> ability_list, List<SYS_PSDEOPPRIV> opprivList) {

        String deName=entity.getString("dename");
        String deLogicName=entity.getString("delogicname");
        JSONObject module=entity.getJSONObject("sysmoudle");
        String moduleId=module.getString("id");
        String moduleName=module.getString("name");
        String sourceId=source.getString("id");
        String sourceName=source.getString("name");
        String dataRangeId=dataRange.getString("id");
        String dataRangeName=dataRange.getString("name");

        String permissionId= DigestUtils.md5DigestAsHex(String.format("%s%s%s%s%s",systemId,moduleId,deName,sourceId,dataRangeId).getBytes());

        String permissionName;
        if(!StringUtils.isEmpty(dataRangeName)){
            permissionName=String.format("[%s]%s[%s]",deLogicName,sourceName,dataRangeName);
        }
        else{
            permissionName=String.format("[%s]%s",deLogicName,sourceName);
        }

        //存资源表
        SYS_PERMISSION sys_permission =new SYS_PERMISSION();
        sys_permission.setPermissionname(permissionName);
        sys_permission.setPssystemid(systemId);
        sys_permission.setPermissionid(permissionId);
        sys_permission.setPermissiontype(OPPriTag);
        sys_permission.setEnable(1);
        sys_permission.setUpdatedate(new Timestamp(new Date().getTime()));
        sys_permission.setCreatedate(new Timestamp(new Date().getTime()));
        ability_list.add(sys_permission);

        //存数据操作能力表
        SYS_PSDEOPPRIV psDEOppriv=new SYS_PSDEOPPRIV();
        psDEOppriv.setPsdeopprivid(permissionId);
        psDEOppriv.setPsdeopprivname(permissionName);
        psDEOppriv.setPssystemid(systemId);
        psDEOppriv.setPssysmoduleid(moduleId);
        psDEOppriv.setPssysmodulename(moduleName);
        psDEOppriv.setPsdataentityid(deName);
        psDEOppriv.setPsdataentityname(deLogicName);
        psDEOppriv.setPssourceid(sourceId);
        psDEOppriv.setPssourcename(sourceName);
        psDEOppriv.setPsdedatarangeid(dataRangeId);
        psDEOppriv.setPsdedatarangename(dataRangeName);
        psDEOppriv.setPssourcetype(permissionType);
        psDEOppriv.setCreatedate(new Timestamp(new Date().getTime()));
        psDEOppriv.setUpdatedate(new Timestamp(new Date().getTime()));
        opprivList.add(psDEOppriv);

    }

    private JSONObject success(String msg){
        JSONObject obj =new JSONObject();
        obj.put("code",1);
        obj.put("msg",msg);
        return obj;
    }
    private JSONObject error(String msg){
        JSONObject obj =new JSONObject();
        obj.put("code",0);
        obj.put("msg",msg);
        return obj;
    }

}
