package com.artfess.sysConfig.persistence.manager.impl;

import com.artfess.base.feign.WorkflowFeignService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.artfess.base.cache.annotation.Cacheable;
import com.artfess.base.cache.annotation.FirstCache;
import com.artfess.base.exception.BaseException;
import com.artfess.base.feign.FormFeignService;
import com.artfess.base.feign.UCFeignService;
import com.artfess.base.model.CommonResult;
import com.artfess.base.query.*;
import com.artfess.base.util.*;
import com.artfess.base.constants.CacheKeyConst;
import com.artfess.sysConfig.persistence.dao.*;
import com.artfess.sysConfig.persistence.manager.*;
import com.artfess.sysConfig.persistence.model.*;
import com.artfess.uc.api.impl.util.ContextUtil;
import org.springframework.stereotype.Service;
import com.artfess.base.manager.impl.BaseManagerImpl;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 
 * <pre> 
 * 描述：portal_sys_app 处理实现类
 * 构建组：x7
 * 作者:qiuxd
 * 邮箱:qiuxd@jee-soft.cn
 * 日期:2020-08-20 15:17:19
 * 版权：广州宏天软件股份有限公司
 * </pre>
 */
@Service("sysAppManager")
public class SysAppManagerImpl extends BaseManagerImpl<SysAppDao, SysApp> implements SysAppManager{

    @Resource
    SysAuthUserManager sysAuthUserManager;
    @Resource
    AppTagsRelationManager appTagsRelationManager;
    @Resource
    CurrentUserService currentUserService;
    @Resource
    SysAppMenuDao sysAppMenuDao;
    @Resource
    PortalAppParamDao portalAppParamDao;
    @Resource
    SysTagDao sysTagDao;
    @Resource
    AppTagsRelationDao appTagsRelationDao;
    @Resource
    SysTypeManager sysTypeManager;
    @Resource
    SysMenuManager sysMenuManager;
    @Resource
    SysAuthUserDao sysAuthUserDao;
    @Resource
    UCFeignService ucFeignService;
    @Resource
    FormFeignService formFeignService;
    @Resource
    SysModuleManager sysModuleManager;
    @Resource
    WorkflowFeignService workflowFeignService;

    @Override
    @Transactional
    public void create(SysApp sysApp){
        String id = UniqueIdUtil.getSuid();
        sysApp.setId(id);
        sysApp.setIsPublish(SysApp.NOT_PUBLISH);
        baseMapper.insert(sysApp);

        //新建默认为任何人权限
        sysAuthUserManager.createDefault(id);
    }

    @Override
    public List<SysApp> queryByAuth(SysApp sysApp) throws Exception {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("is_publish_",SysApp.IS_PUBLISH);
        queryWrapper.eq("menu_id_",sysApp.getMenuId());
        List<SysApp> sysApps = list(queryWrapper);
        if (ContextUtil.getCurrentUser().isAdmin()){
            return sysApps;
        }
        if (BeanUtils.isNotEmpty(sysApps)) {
            List<String> ids = new ArrayList<>();
            for (SysApp app : sysApps) {
                ids.add(app.getId());
            }
            List<String> authIds = sysAuthUserManager.filterAuth(ids);
            if(BeanUtils.isEmpty(authIds)){
                return new ArrayList<>();
            }else{
                return sysApps.parallelStream()
                        .filter(app -> authIds.contains(app.getId()))
                        .collect(Collectors.toList());
            }
        }else{
            return new ArrayList<>();
        }

//        return sysApps.parallelStream()
//                .filter(app -> sysAuthUserManager.hasRights(app.getId()))
//                .collect(Collectors.toList());
    }

    @Override
    public List<SysApp> queryByFilter(QueryFilter<SysApp> queryFilter) {
        queryFilter.addFilter("is_publish_", SysApp.IS_PUBLISH, QueryOP.EQUAL);
        //应用中心没有分页
        if(BeanUtils.isEmpty(queryFilter.getPageBean())){
            queryFilter.setPageBean(new PageBean(1,PageBean.WITHOUT_PAGE));
        }
        PageList<SysApp> query = this.query(queryFilter);
        if (BeanUtils.isNotEmpty(query.getRows())) {
            if(ContextUtil.getCurrentUser().isAdmin()){
                return query.getRows();
            }else {
                List<String> ids = new ArrayList<>();
                for (SysApp app : query.getRows()) {
                    ids.add(app.getId());
                }
                List<String> authIds = sysAuthUserManager.filterAuth(ids);
                return query.getRows().stream().filter(app -> authIds.contains(app.getId())).collect(Collectors.toList());
            }
        }
        return new ArrayList<>();
    }

    @Override
    public List<SysApp> queryByTagIds(String menuId, List<Map<String, String>> maps) {
        QueryWrapper qw = new QueryWrapper();
        qw.eq("is_publish_",SysApp.IS_PUBLISH);
        qw.eq("menu_id_",menuId);
        if (BeanUtils.isNotEmpty(maps)) {
            Set<String> appIds = getAppIdByTags(maps);
            if (BeanUtils.isNotEmpty(appIds)) {
                qw.in("id_",appIds);
            }else{
                //获取到满足条件的id值为空直接返回
                return new ArrayList<>();
            }
        }

        List<SysApp> sysApps = list(qw);
        if(ContextUtil.getCurrentUser().isAdmin()){
            return sysApps;
        }
        return sysApps.stream()
                .filter(app -> sysAuthUserManager.hasRights(app.getId()))
                .collect(Collectors.toList());

    }

    //获取多个应用ID
    private Set<String> getAppIdByTags(List<Map<String,String>> maps){
        Set<String> relList = new HashSet<>();
        for (Map<String, String> map : maps) {
            String tagIds = map.get("tagIds");
            if(StringUtil.isEmpty(tagIds)){
                continue;
            }
            Set<String> list = appTagsRelationManager.getAppIdsByTagIds(tagIds.split(","));
            if(BeanUtils.isEmpty(relList)){
                relList = list;
            }else{
                relList.retainAll(list);
                //如果移除后为空（不存在交集），则直接返回空
                if(relList.isEmpty()){
                    return new HashSet<>();
                }
            }
        }
        return relList;
    }

    @Cacheable(value = CacheKeyConst.EIP_SYS_APP_AUTH_MENU, key = "#userId", firstCache = @FirstCache(expireTime = 10, timeUnit = TimeUnit.MINUTES))
    @Override
    public List<String> getValidMenu(String userId) {
        // 获得流程分管授权与用户相关的信息集合的流程权限内容
        Map<String,Set<String>> userRightMap=currentUserService.getUserRightMap();
        //用户权限列表
        Map<String, String> userRightMapStr=currentUserService.getMapStringByMayList(userRightMap);
        List<String> ids = baseMapper.getValidMenu(); //有权限的ID
        if(BeanUtils.isEmpty(ids)){
            return new ArrayList<>();
        }
        /*if(ContextUtil.getCurrentUser().isAdmin()){
            return ids;
        }*/
        return ids.stream().filter(menuId -> sysAuthUserManager.getAuthorizeAppMenuId(menuId,userRightMapStr))
                .collect(Collectors.toList());

    }

    @Override
    public Map<String, String> exportData(List<String> ids) throws Exception {
        Map<String, String> map = new HashMap<>();
        SysAppXmlList sysAppXmlList = new SysAppXmlList();
        for (String id : ids) {
            QueryWrapper wrapper = new QueryWrapper();
            wrapper.eq("app_id_", id);
            List<SysAppMenu> sysAppMenuList = sysAppMenuDao.selectList(wrapper);
            List<SysAppMenu> sysAppMenuTree = BeanUtils.listToTree(sysAppMenuList);
            List<PortalAppParam> portalAppParamList = portalAppParamDao.selectList(wrapper);
            List<SysTag> sysTagList = sysTagDao.getSysTagsByAppId(id);
            Map<String,Object> condition = new HashMap<>();
            condition.put("authorize_id_", id);
            List<SysAuthUser> sysAuthUserList = sysAuthUserDao.selectByMap(condition);
            for (SysAuthUser sysAuthUser : sysAuthUserList){
                String rightType = sysAuthUser.getRightType();
                String ownerId = sysAuthUser.getOwnerId();
                if ("user".equals(rightType)){
                    CommonResult<JsonNode> result = ucFeignService.getUserById(ownerId);
                    if (BeanUtils.isNotEmpty(result)){
                        JsonNode userNode = result.getValue();
                        String account = JsonUtil.getString(userNode, "account");
                        sysAuthUser.setOwnerCode(account);
                    }
                }else if ("org".equals(rightType)){
                    ObjectNode orgObjNode = ucFeignService.getOrgByIdOrCode(ownerId);
                    if (BeanUtils.isNotEmpty(orgObjNode)){
                        String code = orgObjNode.get("code").asText();
                        sysAuthUser.setOwnerCode(code);
                    }
                }else if ("pos".equals(rightType)){
                    CommonResult<ObjectNode> result = ucFeignService.getPostByIdOrCode(ownerId);
                    if (BeanUtils.isNotEmpty(result)){
                        ObjectNode posObjNode = result.getValue();
                        String code = posObjNode.get("code").asText();
                        sysAuthUser.setOwnerCode(code);
                    }
                }else if ("role".equals(rightType)){
                    CommonResult<ObjectNode> result = ucFeignService.getRoleByIdOrCode(ownerId);
                    if (BeanUtils.isNotEmpty(result)){
                        ObjectNode roleObjNode = result.getValue();
                        String code = roleObjNode.get("code").asText();
                        sysAuthUser.setOwnerCode(code);
                    }
                }
            }
            SysAppXml sysAppXml = new SysAppXml();
            SysApp sysApp = this.get(id);
            String sysMenuId = sysApp.getMenuId();
            if (StringUtil.isNotEmpty(sysMenuId)){
                SysMenu sysMenu = sysMenuManager.get(sysApp.getMenuId());
                if (sysMenu != null){
                    sysApp.setMenuAlias(sysMenu.getAlias());
                }
            }
            String content = sysApp.getContent();
            if (sysApp.getType() != null && BeanUtils.isNotEmpty(content) && content.startsWith("{") && content.endsWith("}")) {
                JsonNode contentNode = JsonUtil.toJsonNode(content);
                String contentId = contentNode.get("id").asText();
                if (BeanUtils.isNotEmpty(contentId) && !"null".equals(contentId)) {
                    String contentAlias = null;
                    switch (sysApp.getType()) {
                        // 常规应用
                        case 1:
                            break;
                        // 表单列表
                        case 2:
                            ObjectNode formDataTemplateObjNode = formFeignService.getFormDataTemplateById(contentId);
                            if (BeanUtils.isNotEmpty(formDataTemplateObjNode)) {
                                contentAlias = formDataTemplateObjNode.get("alias").asText();
                            }
                            break;
                        // 自定义视图
                        case 3:
                            contentAlias = contentNode.get("alias").asText();
                            break;
                        // 图表(customChart)
                        case 4:
                            ObjectNode customChartObjNode = formFeignService.getCustomChartById(contentId);
                            if (BeanUtils.isNotEmpty(customChartObjNode)) {
                                contentAlias = customChartObjNode.get("alias").asText();
                            }
                            break;
                        // 网页跳转
                        case 5:
                            break;
                        // 表单
                        case 6:
                            contentAlias = contentNode.get("key").asText();
                            break;
                        // 流程模块
                        case 7:
                            SysModule sysModule = sysModuleManager.get(contentId);
                            if (BeanUtils.isNotEmpty(sysModule)) {
                                contentAlias = sysModule.getCode();
                            }
                            break;
                        // 流程
                        case 8:
                            contentAlias = contentNode.get("key").asText();
                            break;
                        default:
                            break;
                    }
                    if (BeanUtils.isNotEmpty(contentAlias) && !"null".equals(contentAlias)) {
                        sysApp.setContentAlias(contentAlias);
                    }

                }
            }
            sysAppXml.setSysApp(sysApp);
            sysAppXml.setSysAppMenuList(sysAppMenuTree);
            sysAppXml.setPortalAppParamList(portalAppParamList);
            sysAppXml.setSysTagList(sysTagList);
            sysAppXml.setSysAuthUserList(sysAuthUserList);
            sysAppXmlList.addSysAppXml(sysAppXml);
        }
        try {
            String xml = JAXBUtil.marshall(sysAppXmlList, SysAppXmlList.class);
            map.put("sysApps.portal.xml", xml);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("导出失败！" + e.getMessage(), e);
        }
        return map;
    }

    @Override
    @Transactional
    public void importData(MultipartFile file) {
        String unZipFilePath = null;
        try {
            String rootRealPath = Paths.get(FileUtil.getIoTmpdir(), "attachFiles/unZip").toString();
            FileUtil.createFolder(rootRealPath, true);
            ZipUtil.unZipFile(file, rootRealPath);
            String name = file.getOriginalFilename();
            String fileDir = StringUtil.substringBeforeLast(name, ".");
            unZipFilePath = Paths.get(rootRealPath, fileDir).toString();
            String xml = FileUtil.readFile(Paths.get(unZipFilePath, "sysApps.portal.xml").toString());
            if (StringUtil.isEmpty(xml)) {
                throw new BaseException("导入的xml文件没有内容！");
            }
            SysAppXmlList list = (SysAppXmlList) JAXBUtil.unmarshall(xml, SysAppXmlList.class);
            List<SysAppXml> sysAppXmlList = list.getSysAppXmlList();
            for (SysAppXml sysAppXml : sysAppXmlList) {
                importData(sysAppXml);
            }
        } catch (Exception e) {
            throw new BaseException(e.getMessage(), e);
        } finally {
            if (StringUtil.isNotEmpty(unZipFilePath)) {
                File formDir = new File(unZipFilePath);
                if (formDir.exists()) {
                    FileUtil.deleteDir(formDir);
                }
            }
        }
    }

    private void importData(SysAppXml sysAppXml) throws IOException {
        SysApp sysApp = sysAppXml.getSysApp();
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("name_", sysApp.getName());
        List<SysApp> sysAppList = baseMapper.selectList(wrapper);
        if (sysAppList != null && !sysAppList.isEmpty()) {
            ThreadMsgUtil.addMapMsg2("sysAppsSkipped", String.format("<div style='margin-left:12px; margin-top:6px;'>%s</div>", sysApp.getName() + ""));
            return;
        }
        String appId = UniqueIdUtil.getSuid();
        sysApp.setId(appId);
        String sysMenuAlias = sysApp.getMenuAlias();
        if (StringUtil.isNotEmpty(sysMenuAlias)){
            SysMenu sysMenu = sysMenuManager.getByAlias(sysMenuAlias);
            if (BeanUtils.isNotEmpty(sysMenu)){
                sysApp.setMenuId(sysMenu.getId());
            }
        }
        String contentAlias = sysApp.getContentAlias();
        String content = sysApp.getContent();
        if (sysApp.getType() != null && BeanUtils.isNotEmpty(contentAlias) && BeanUtils.isNotEmpty(content) && content.startsWith("{") && content.endsWith("}")) {
            String contentId = null;
            String contentName = null;
            switch (sysApp.getType()) {
                // 常规应用
                case 1:
                    break;
                // 表单列表
                case 2:
                    ObjectNode formDataTemplateObjNode = formFeignService.getFormDataTemplateByAlias(contentAlias);
                    if (BeanUtils.isNotEmpty(formDataTemplateObjNode)) {
                        contentId = formDataTemplateObjNode.get("id").asText();
                        contentName = formDataTemplateObjNode.get("name").asText();
                    }
                    break;
                // 自定义视图
                case 3:
                    ObjectNode queryViewObjNode = formFeignService.getQueryViewByAlias(contentAlias);
                    if (BeanUtils.isNotEmpty(queryViewObjNode)) {
                        contentId = queryViewObjNode.get("id").asText();
                        contentName = queryViewObjNode.get("name").asText();
                    }
                    break;
                // 图表(customChart)
                case 4:
                    ObjectNode customChartObjNode = formFeignService.getCustomChartByAlias(contentAlias);
                    if (BeanUtils.isNotEmpty(customChartObjNode)) {
                        contentId = customChartObjNode.get("id").asText();
                        contentName = customChartObjNode.get("name").asText();
                    }
                    break;
                // 网页跳转
                case 5:
                    break;
                // 表单
                case 6:
                    ObjectNode formObjNode = formFeignService.getFormDefByKey(contentAlias);
                    if (BeanUtils.isNotEmpty(formObjNode)) {
                        contentId = formObjNode.get("id").asText();
                        contentName = formObjNode.get("name").asText();
                    }
                    break;
                // 流程模块
                case 7:
                    QueryWrapper<SysModule> queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq("code_", contentAlias);
                    SysModule sysModule = sysModuleManager.getOne(queryWrapper, false);
                    if (BeanUtils.isNotEmpty(sysModule)) {
                        contentId = sysModule.getId();
                        contentName = sysModule.getName();
                    }
                    break;
                // 流程
                case 8:
                    ObjectNode procDefObjNode = workflowFeignService.getProcDefByDefKey(contentAlias);
                    if (BeanUtils.isNotEmpty(procDefObjNode)) {
                        contentId = procDefObjNode.get("defId").asText();
                        contentName = procDefObjNode.get("name").asText();
                    }
                    break;
                default:
                    break;
            }
            ObjectNode contentObjNode = JsonUtil.toJsonNode(content).deepCopy();
            if (BeanUtils.isNotEmpty(contentId) && !"null".equals(contentId)) {
                contentObjNode.put("id", contentId);
            }
            if (BeanUtils.isNotEmpty(contentName) && !"null".equals(contentName)) {
                contentObjNode.put("name", contentName);
            }
            sysApp.setContent(contentObjNode.toString());
        }
        baseMapper.insert(sysApp);
        wrapper = new QueryWrapper();
        wrapper.eq("app_id_", appId);
        List<SysAppMenu> sysAppMenuList = sysAppXml.getSysAppMenuList();
        if (BeanUtils.isNotEmpty(sysAppMenuList)){
            for (SysAppMenu sysAppMenu : sysAppMenuList){
                String menuId = UniqueIdUtil.getSuid();
                sysAppMenu.setId(menuId);
                sysAppMenu.setParentId("0");
                sysAppMenu.setAppId(appId);
                sysAppMenuDao.insert(sysAppMenu);
                if ("true".equals(sysAppMenu.getIsParent())){
                    for (SysAppMenu sysAppMenuChild : (List<SysAppMenu>)sysAppMenu.getChildren()) {
                        String menuChildId = UniqueIdUtil.getSuid();
                        sysAppMenuChild.setId(menuChildId);
                        sysAppMenuChild.setParentId(menuId);
                        sysAppMenuChild.setAppId(appId);
                        sysAppMenuDao.insert(sysAppMenuChild);
                    }
                }
            }
        }
        List<PortalAppParam> portalAppParamList = sysAppXml.getPortalAppParamList();
        if (BeanUtils.isNotEmpty(portalAppParamList)){
            for (PortalAppParam portalAppParam : portalAppParamList){
                String paramId = UniqueIdUtil.getSuid();
                portalAppParam.setId(paramId);
                portalAppParam.setAppId(appId);
                portalAppParamDao.insert(portalAppParam);
            }
        }
        List<SysTag> sysTagList = sysAppXml.getSysTagList();
        if (BeanUtils.isNotEmpty(sysTagList)){
            for (SysTag sysTag : sysTagList){
                SysType sysType = sysTypeManager.getByTypeKeyAndGroupKey("TAG", sysTag.getTypeKey());
                if (sysType != null){
                    wrapper = new QueryWrapper();
                    wrapper.eq("key_", sysTag.getKey());
                    SysTag existSysTag = null;
                    List<SysTag> existSysTags = sysTagDao.selectList(wrapper);
                    if (BeanUtils.isNotEmpty(existSysTags)){
                        existSysTag = existSysTags.get(0);
                    }
                    String tagId = UniqueIdUtil.getSuid();
                    if (BeanUtils.isNotEmpty(existSysTag)){
                        tagId = existSysTag.getId();
                    }else{
                        sysTag.setId(tagId);
                        sysTag.setTypeId(sysType.getId());
                        sysTagDao.insert(sysTag);
                    }
                    String relationId = UniqueIdUtil.getSuid();
                    AppTagsRelation appTagsRelation = new AppTagsRelation();
                    appTagsRelation.setId(relationId);
                    appTagsRelation.setAppId(appId);
                    appTagsRelation.setTagId(tagId);
                    appTagsRelationDao.insert(appTagsRelation);
                }
            }
        }
        List<SysAuthUser> sysAuthUserList = sysAppXml.getSysAuthUserList();
        if (BeanUtils.isEmpty(sysAuthUserList)){
            sysAuthUserManager.createDefault(appId);
        }else{
            for (SysAuthUser sysAuthUser : sysAuthUserList){
                String authId = UniqueIdUtil.getSuid();
                sysAuthUser.setId(authId);
                sysAuthUser.setAuthorizeId(appId);
                String rightType = sysAuthUser.getRightType();
                String ownerCode = sysAuthUser.getOwnerCode();
                if ("user".equals(rightType)){
                    JsonNode userNode = ucFeignService.getUser(ownerCode, null);
                    if (BeanUtils.isNotEmpty(userNode)){
                        String ownerId = JsonUtil.getString(userNode, "id");
                        String ownerName = JsonUtil.getString(userNode, "fullname");
                        sysAuthUser.setOwnerId(ownerId);
                        sysAuthUser.setOwnerName(ownerName);
                    }
                }else if ("org".equals(rightType)){
                    ObjectNode orgObjNode = ucFeignService.getOrgByIdOrCode(ownerCode);
                    if (BeanUtils.isNotEmpty(orgObjNode)){
                        String ownerId = orgObjNode.get("id").asText();
                        String ownerName = orgObjNode.get("name").asText();
                        sysAuthUser.setOwnerId(ownerId);
                        sysAuthUser.setOwnerName(ownerName);
                    }
                }else if ("pos".equals(rightType)){
                    CommonResult<ObjectNode> result = ucFeignService.getPostByIdOrCode(ownerCode);
                    if (BeanUtils.isNotEmpty(result)){
                        ObjectNode posObjNode = result.getValue();
                        String ownerId = posObjNode.get("id").asText();
                        String ownerName = posObjNode.get("name").asText();
                        sysAuthUser.setOwnerId(ownerId);
                        sysAuthUser.setOwnerName(ownerName);
                    }
                }else if ("role".equals(rightType)){
                    CommonResult<ObjectNode> result = ucFeignService.getRoleByIdOrCode(ownerCode);
                    if (BeanUtils.isNotEmpty(result)){
                        ObjectNode roleObjNode = result.getValue();
                        String ownerId = roleObjNode.get("id").asText();
                        String ownerName = roleObjNode.get("name").asText();
                        sysAuthUser.setOwnerId(ownerId);
                        sysAuthUser.setOwnerName(ownerName);
                    }
                }
                sysAuthUserDao.insert(sysAuthUser);
            }
        }
        ThreadMsgUtil.addMapMsg2("sysAppsSaved", String.format("<div style='margin-left:12px; margin-top:6px;'>%s</div>", sysApp.getName() + ""));
    }
}
