package com.hotent.portal.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.google.common.collect.Lists;
import com.hotent.base.aop.OpenApiProcessor;
import com.hotent.base.cache.annotation.Cacheable;
import com.hotent.base.cache.annotation.FirstCache;
import com.hotent.base.constants.CacheKeyConst;
import com.hotent.base.context.BaseContext;
import com.hotent.base.entity.URIEntity;
import com.hotent.base.enums.ResponseErrorEnums;
import com.hotent.base.exception.BaseException;
import com.hotent.base.feign.BpmModelFeignService;
import com.hotent.base.feign.BpmRuntimeFeignService;
import com.hotent.base.feign.FormFeignService;
import com.hotent.base.feign.UCFeignService;
import com.hotent.base.handler.MultiTenantHandler;
import com.hotent.base.handler.MultiTenantIgnoreResult;
import com.hotent.base.manager.impl.BaseManagerImpl;
import com.hotent.base.model.CommonResult;
import com.hotent.base.query.*;
import com.hotent.base.util.AppUtil;
import com.hotent.base.util.BeanUtils;
import com.hotent.base.util.JsonUtil;
import com.hotent.base.util.StringUtil;
import com.hotent.portal.model.PortalBizSystem;
import com.hotent.portal.model.PortalBizSystemAuth;
import com.hotent.portal.model.PortalUrlPermission;
import com.hotent.portal.persistence.dao.PortalBizSystemAuthDao;
import com.hotent.portal.persistence.dao.PortalBizSystemDao;
import com.hotent.portal.persistence.dao.PortalUrlPermissionDao;
import com.hotent.portal.persistence.manager.PortalBizSystemAuthManager;
import com.hotent.portal.persistence.manager.PortalMsgSendLogManager;
import com.hotent.portal.service.PortalBizSystemManager;
import com.hotent.portal.service.PortalUrlPermissionManager;
import com.hotent.sys.persistence.manager.SysPropertiesManager;
import com.hotent.uc.api.impl.util.ContextUtil;
import com.hotent.uc.api.model.IUser;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 *  服务实现类
 *
 * @company 广州宏天软件股份有限公司
 * @author cola
 * @since 2021-08-25
 */
@Service
public class PortalBizSystemManagerImpl extends BaseManagerImpl<PortalBizSystemDao, PortalBizSystem> implements PortalBizSystemManager {
    // 外部接口的redis前缀
    private final String Prefix="openApi:";
    private final Logger logger= LoggerFactory.getLogger(PortalBizSystemManagerImpl.class);
    @Value("${spring.application.name:base}")
    private String applicationName;

    @Autowired
    PortalBizSystemDao portalBizSystemDao;
    @Autowired
    BaseContext baseContext;
    @Autowired
    PortalUrlPermissionManager portalUrlPermissionManager;
    @Autowired
    PortalMsgSendLogManager portalMsgSendLogManager;
    @Autowired
    SysPropertiesManager sysPropertiesManager;
    @Autowired
    UCFeignService ucFeignService;
    @Autowired
    PortalBizSystemAuthDao portalBizSystemAuthDao;
    @Autowired
    PortalBizSystemAuthManager portalBizSystemAuthManager;
    @Autowired
    PortalUrlPermissionDao portalUrlPermissionDao;

    @Autowired
    BpmModelFeignService bpmModelFeignService;
    @Autowired
    BpmRuntimeFeignService bpmRuntimeFeignService;
    @Autowired
    FormFeignService formFeignService;



    @Override
    @Transactional(rollbackFor = Exception.class)
    public CommonResult<String> savePortalBizSystem(PortalBizSystem portalBizSystem) {
        // 先判断有没有该系统编码，有的话，不用再插入
        QueryWrapper<PortalBizSystem> wrapper = new QueryWrapper<>();
        wrapper.eq("SYS_CODE_",portalBizSystem.getSysCode());
        PortalBizSystem bizSystem =null;
        try(MultiTenantIgnoreResult result = MultiTenantHandler.setThreadLocalIgnore()){
            bizSystem = portalBizSystemDao.selectOne(wrapper);
        }catch (Exception e){
            e.printStackTrace();
        }
        if (BeanUtils.isNotEmpty(bizSystem)){
            return new CommonResult<>(false,"该系统编码在本租户或者其他租户平台已存在，请勿重复添加","");
        }
        portalBizSystem.setCreateBy(baseContext.getCurrentUserId());
        portalBizSystem.setEnabled("0");
        portalBizSystem.setIsDele("0");
        portalBizSystem.setCreateOrgId(baseContext.getCurrentOrgId());
        int insert = portalBizSystemDao.insert(portalBizSystem);
        portalBizSystemAuthManager.batchSave(portalBizSystem);
        if(insert!=1) {
            return new CommonResult<>(ResponseErrorEnums.FAIL_OPTION, null);
        }
        return new CommonResult<>(ResponseErrorEnums.SUCCESS_OPTION,null);
    }

    @Transactional
    @Override
    public CommonResult updatePortalBizSystem(PortalBizSystem portalBizSystem) {
        // 前端传递过来的enabled字段需要转译一下
        if ("true".equals(portalBizSystem.getEnabled())) {
            portalBizSystem.setEnabled("0");
        }else{
            portalBizSystem.setEnabled("1");
        }
        portalBizSystem.setUpdateBy(baseContext.getCurrentUserId());
        portalBizSystemDao.updateById(portalBizSystem);
        QueryWrapper<PortalBizSystemAuth> authQueryWrapper = new QueryWrapper<>();
        authQueryWrapper.eq("SYS_CODE_",portalBizSystem.getSysCode()).eq("CREATE_BY_",baseContext.getCurrentUserId());
        portalBizSystemAuthDao.delete(authQueryWrapper);
        portalBizSystemAuthManager.batchSave(portalBizSystem);
        return new CommonResult(true,ResponseErrorEnums.SUCCESS_OPTION.getMessage(),null);
    }

    @Override
    public CommonResult searchById(String id) {
        QueryWrapper<PortalBizSystem> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("ID_",id).eq("IS_DELE_","0");
        PortalBizSystem portalBizSystem = portalBizSystemDao.selectOne(queryWrapper);
        QueryWrapper<PortalBizSystemAuth> authQueryWrapper = new QueryWrapper<>();
        authQueryWrapper.eq("SYS_CODE_",portalBizSystem.getSysCode()).eq("IS_DELE_","0");
        List<PortalBizSystemAuth> auths = portalBizSystemAuthDao.selectList(authQueryWrapper);
        portalBizSystem.setManagerList(auths);
        return new CommonResult().value(portalBizSystem);
    }

    @Override
    public CommonResult getOpenApiList() {
        PortalBizSystemManagerImpl bean = AppUtil.getBean(getClass());
        Set<URIEntity> openApiList = bean.getOpenApiListFromCache("openApi");
        Map<String,Map<String,List<URIEntity>>> map=new HashMap<>();
        openApiList.stream().forEach(item->{
            if (map.get(item.getModuleName())==null){
                ArrayList<URIEntity> descriptionList = new ArrayList<URIEntity>();
                Map<String,List<URIEntity>> functionMap=new HashMap<>();
                descriptionList.add(item);
                functionMap.put(item.getFunction(),descriptionList);
                map.put(item.getModuleName(), functionMap);
            }else{
                Map<String, List<URIEntity>> treeMap = map.get(item.getModuleName());
                List<URIEntity> descriptionList = treeMap.get(item.getFunction());
                if(descriptionList==null || descriptionList.size()==0){
                    descriptionList = new ArrayList<URIEntity>();
                }
                descriptionList.add(item);
                treeMap.put(item.getFunction(),descriptionList);
                map.put(item.getModuleName(),treeMap);
            }
        });
        return new CommonResult().value(map);
    }

    @Override
    public CommonResult checkSysCode(String sysCode,String secretKey) throws Exception {
        QueryWrapper<PortalBizSystem> wrapper = new QueryWrapper<>();
        if (StringUtil.isNotEmpty(secretKey)){
            wrapper.eq("SECRET_KEY_",secretKey);
        }
        wrapper.eq("SYS_CODE_",sysCode);
        PortalBizSystem res = null;
        try(MultiTenantIgnoreResult result = MultiTenantHandler.setThreadLocalIgnore()){
            res = portalBizSystemDao.selectOne(wrapper);
        }
        if (res==null ){
            return new CommonResult(false,"系统编码或系统密匙不正确",null);
        }else if ("1".equals(res.getEnabled())){
            return new CommonResult(false,"该外部系统已禁用，认证失败",null);
        }
        // 需要返回机器人ID（其实就是uc_user表记录的id）
        return new CommonResult(true,"认证信息正确",res.getRobotId());
    }

    @Override
    public CommonResult getPortalBizSystemBySysCode(String sysCode) {
        QueryWrapper<PortalBizSystem> wrapper = new QueryWrapper<>();
        wrapper.eq("SYS_CODE_",sysCode);
        PortalBizSystem portalBizSystem = portalBizSystemDao.selectOne(wrapper);
        if (portalBizSystem==null){
            return new CommonResult(false,"查无此系统编码",null);
        }
        return new CommonResult(true,"查询成功",portalBizSystem.getBpmMsgQueue());
    }

    @Override
    public CommonResult getPortalBizSystemUrlBySysCode(String sysCode) {
        QueryWrapper<PortalBizSystem> wrapper = new QueryWrapper<>();
        wrapper.eq("SYS_CODE_",sysCode);
        PortalBizSystem portalBizSystem = portalBizSystemDao.selectOne(wrapper);
        if (portalBizSystem==null){
            return new CommonResult(false,"查无此系统编码",null);
        }
        return new CommonResult(true,"查询成功",portalBizSystem.getRootAddress());
    }

    @Override
    public CommonResult getPortalBizSystemByCode(String code) {
        QueryWrapper<PortalBizSystem> wrapper = new QueryWrapper<>();
        wrapper.eq("SYS_CODE_",code);
        PortalBizSystem portalBizSystem = portalBizSystemDao.selectOne(wrapper);
        if (portalBizSystem==null){
            return new CommonResult(false,"查无此系统编码",null);
        }
        return new CommonResult(true,"查询成功",portalBizSystem);
    }

    /**
     * 判断该路径是否已经被授权
     * @param sysCode 系统编码
     * @param secretKey 系统密匙
     * @param uri 访问的路径
     * @param tenantId 租户Id
     * @return
     */
    @Override
    public CommonResult checkSysCodeAndUri(String sysCode, String secretKey, String uri,String tenantId) {
        QueryWrapper<PortalBizSystem> wrapper = new QueryWrapper<>();
        if (StringUtil.isNotEmpty(secretKey)){
            wrapper.eq("SECRET_KEY_",secretKey);
        }
        wrapper.eq("SYS_CODE_",sysCode);
        PortalBizSystem res = portalBizSystemDao.selectOne(wrapper);
        if (res==null){
            return new CommonResult(false,"系统编码或系统密匙不正确",null);
        }
        QueryWrapper<PortalUrlPermission> portalUrlWrapper = new QueryWrapper<>();
        portalUrlWrapper.eq("SYS_ID_",res.getSysCode()).eq("AUTH_URL_",uri);
        PortalUrlPermission one = portalUrlPermissionManager.getOne(portalUrlWrapper);
        if (one==null){
            return new CommonResult(false,"当前路径，您无访问权限",null);
        }
        // 需要返回机器人ID（其实就是uc_user表记录的id）
        return new CommonResult(true,"认证信息正确",res.getRobotId());
    }

	@Override
	public List<PortalBizSystem> getList() {
		QueryWrapper<PortalBizSystem> wrapper = new QueryWrapper<PortalBizSystem>();
		wrapper.eq("ENABLED_", "0");
        return baseMapper.selectList(wrapper);
	}

    /**
     * 查询服务列表（目前用于流程节点接口事件中）
     * 系统微服务列表直接设置值
     * 接口中使用${code}存入数据库中，在调用的时候再解析出实际地址
     * 微服务的实际地址在【系统管理 > 系统属性】中配置，外部系统实际地址在【集成中心 > 外部系统管理中配置】
     * @return
     */
    @Override
    public List<PortalBizSystem> getServiceList() throws JsonProcessingException {
        List<PortalBizSystem> serviceList = Lists.newArrayList();
        String arrayString = sysPropertiesManager.getByAlias("service.address");

        if(StringUtils.isNotBlank(arrayString)) {
            arrayString = arrayString.replace("\\\"", "\"");
            ObjectMapper mapper = JsonUtil.getMapper();
            JsonNode jsonNode = mapper.readTree(arrayString);
            if (!Objects.isNull(jsonNode) && jsonNode.isArray()) {
                PortalBizSystem tmp = null;
                ArrayNode arrayNode = (ArrayNode) jsonNode;
                for (JsonNode jn : arrayNode) {
                    tmp = new PortalBizSystem();
                    tmp.setSysName(jn.get("code").asText());
                    tmp.setSysCode(jn.get("code").asText());
                    tmp.setRootAddress(jn.get("value").asText());
                    serviceList.add(tmp);
                }
            }
        }

        QueryWrapper<PortalBizSystem> wrapper = new QueryWrapper<PortalBizSystem>();
        wrapper.eq("ENABLED_", "0");
        wrapper.select("SYS_CODE_","SYS_NAME_,ROOT_ADDRESS_");
        List<PortalBizSystem> portalBizSystemList = baseMapper.selectList(wrapper);
        if(CollectionUtils.isNotEmpty(portalBizSystemList)){
            serviceList.addAll(portalBizSystemList);
        }

        return serviceList;
    }

    @Override
    public CommonResult getAuthUserBySystemCode(QueryFilter queryFilter) {
        String sysCode =(String) queryFilter.getParams().get("sysCode");
        boolean isAdmin = ContextUtil.getCurrentUser().isAdmin();
        String curUserId=null;
        if (!isAdmin){
           curUserId=ContextUtil.getCurrentUser().getUserId();
        }
        String managerName=null;
        String account=null;
        if (BeanUtils.isNotEmpty(queryFilter.getQuerys())){
            QueryField managerField = (QueryField)queryFilter.getQuerys().get(0);
            QueryField accountField = (QueryField)queryFilter.getQuerys().get(1);
            managerName=(String) managerField.getValue();
            account=(String)accountField.getValue();
        }
        IPage<PortalBizSystemAuth> page=new Page<>(queryFilter.getPageBean().getPage(),queryFilter.getPageBean().getPageSize());
        IPage<PortalBizSystemAuth> iPage = portalBizSystemAuthDao.selectBizSystemAuth(page, sysCode,managerName,account,isAdmin,curUserId);
        return CommonResult.ok().value(iPage);
    }

    @Override
    public CommonResult deleteAuthByIds(String userIds) {
        String[] ids = userIds.split(",");
        portalBizSystemAuthDao.deleteBatchIds(Arrays.asList(ids));
        return CommonResult.ok();
    }

    @Override
    @Transactional
    public CommonResult addAuthByUserIdAndSysCode(String userIds, String sysCode) {
        String[] ids = userIds.split(",");
        QueryWrapper<PortalBizSystem> wrapper = new QueryWrapper<>();
        wrapper.eq("SYS_CODE_",sysCode);
        PortalBizSystem  portalBizSystem = portalBizSystemDao.selectOne(wrapper);
        for (String userId : ids) {
            PortalBizSystemAuth auth=new PortalBizSystemAuth();
            auth.setSysCode(sysCode);
            auth.setManagerId(userId);
            CommonResult<JsonNode> user = ucFeignService.getUserById(userId);
            String username = user.getValue().get("fullname").asText();
            auth.setManagerName(username);
            auth.setIsDele("0");
            auth.setCreateBy(ContextUtil.getCurrentUserId());
            auth.setSysName(portalBizSystem.getSysName());
            auth.setAccount(user.getValue().get("account").asText());
            try {
                portalBizSystemAuthDao.insert(auth);
            }catch (Exception e){
                // 唯一索引导致的预期异常
                logger.error("插入管理员时异常:{}",e.getMessage());
            }
        }
        return CommonResult.ok();
    }

    /**
     * 根据外部系统的编码来删除，删除的同时，需要把该外部系统配置过的管理人员也一并删除
     * @param
     * @return
     */
    @Override
    @Transactional
    public CommonResult deleteBySysCode(String sysCodes) {
        String[] sysCodeArray = sysCodes.split(",");
        for (String sysCode : sysCodeArray) {
            QueryWrapper<PortalBizSystem> wrapper = new QueryWrapper<>();
            wrapper.eq("SYS_CODE_",sysCode);
            PortalBizSystem portalBizSystem = portalBizSystemDao.selectOne(wrapper);
            if (portalBizSystem!=null){
                QueryWrapper<PortalUrlPermission> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("SYS_ID_",sysCode);
                List<PortalUrlPermission> urlPermissions = portalUrlPermissionDao.selectList(queryWrapper);
                if (BeanUtils.isNotEmpty(urlPermissions)){
                    throw new BaseException("请先删除 "+portalBizSystem.getSysName()+" 系统授权的外部接口");
                }
                QueryWrapper<PortalBizSystemAuth> systemAuthQueryWrapper = new QueryWrapper<>();
                systemAuthQueryWrapper.eq("sys_code_",sysCode);
                portalBizSystemAuthDao.delete(systemAuthQueryWrapper);
                LambdaQueryWrapper<PortalBizSystem> portalBizSystemWrapper = Wrappers.<PortalBizSystem>lambdaQuery();
                portalBizSystemWrapper.eq(PortalBizSystem::getSysCode,sysCode);
                portalBizSystemDao.delete(portalBizSystemWrapper);
            }
        }
        return CommonResult.ok().message(ResponseErrorEnums.SUCCESS_OPTION.getMessage());
    }


    /**
     * 除admin外，创建人和管理员在列表中可以查看到该记录并进行修改
     * @param queryFilter
     * @return
     */
    @Override
    public PageList queryData(QueryFilter queryFilter) {
        IUser user = ContextUtil.getCurrentUser();
        boolean isAdmin=user.isAdmin();
        PageBean pageBean = queryFilter.getPageBean();
        String sysCode = null;
        String orderFields = "";
        if(queryFilter.getQuerys().size()!=0){
            List<QueryField> querys = queryFilter.getQuerys();
            QueryField queryField =querys.get(0);
            sysCode=(String) queryField.getValue();
        }
        if(queryFilter.getSorter().size()>0){
            List<FieldSort> fieldSorts = queryFilter.getSorter();
            for(FieldSort fieldSort:fieldSorts){
                if(fieldSort.getProperty().equalsIgnoreCase("ENABLED")){
                    orderFields = orderFields+", "+fieldSort.getProperty()+"_  "+fieldSort.getDirection();
                }else {
                    orderFields = orderFields+", "+fieldSort.getProperty()+" "+fieldSort.getDirection();
                }
            }
            orderFields = orderFields.substring(2);
        }
        IPage<PortalBizSystem> result=portalBizSystemDao.selectData(convert2IPage(pageBean),isAdmin,user.getUserId(),sysCode,orderFields);
        result.getRecords().forEach(t->{
            CommonResult<JsonNode> userNode = ucFeignService.getUserById(t.getCreateBy());
            if (userNode.getState()){
                t.setCreatorName(userNode.getValue().get("fullname").asText());
            }
        });
        return new PageList<PortalBizSystem>(result);
    }

    @Override
    public Set<URIEntity> getOpenApiListFromCacheOut() {
        PortalBizSystemManagerImpl bean = AppUtil.getBean(getClass());
        Set<URIEntity> openApiList = bean.getOpenApiListFromCache("openApi");
        return openApiList;
    }

    @Cacheable(value = CacheKeyConst.EIP_SYS_UC_OPEN_API,key = "#openApi", shortExpire = true)
    public Set<URIEntity> getOpenApiListFromCache(String openApi){
        if(!"base".equals(applicationName)){
            Set<URIEntity> result = new CopyOnWriteArraySet<URIEntity>();
            Set<URIEntity> bpmModelURIEntity = bpmModelFeignService.getMicroURIEntity();
            Set<URIEntity> bpmRuntimeURIEntity = bpmRuntimeFeignService.getMicroURIEntity();
            Set<URIEntity> formFeignURIEntity = formFeignService.getMicroURIEntity();
            Set<URIEntity> portalURIEntity = OpenApiProcessor.uriEntitySet;//portal服务
            Set<URIEntity> ucURIEntity = ucFeignService.getMicroURIEntity();
            result.addAll(bpmModelURIEntity);
            result.addAll(bpmRuntimeURIEntity);
            result.addAll(formFeignURIEntity);
            result.addAll(portalURIEntity);
            result.addAll(ucURIEntity);
            return result;
        }

        return OpenApiProcessor.uriEntitySet;
    }
}

