package com.persagy.proxy.dictionary.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.persagy.dmp.basic.model.QueryCriteria;
import com.persagy.dmp.basic.utils.JsonNodeUtils;
import com.persagy.dmp.common.constant.ValidEnum;
import com.persagy.dmp.common.context.AppContext;
import com.persagy.dmp.common.utils.JsonHelper;
import com.persagy.dmp.delivery.entity.ObjectInfoCollect;
import com.persagy.proxy.adm.constant.AdmCommonConstant;
import com.persagy.proxy.adm.constant.AdmDictConstant;
import com.persagy.proxy.adm.request.AdmQueryCriteria;
import com.persagy.proxy.adm.request.AdmResponse;
import com.persagy.proxy.adm.utils.AdmEntityTransferUtil;
import com.persagy.proxy.adm.utils.AdmQueryCriteriaHelper;
import com.persagy.proxy.common.client.DmpDicClient;
import com.persagy.proxy.common.client.DmpRwdClient;
import com.persagy.proxy.common.entity.DmpResult;
import com.persagy.proxy.common.entity.InstanceUrlParam;
import com.persagy.proxy.dictionary.model.AdmObjectType;
import com.persagy.proxy.dictionary.service.IAdmDictBaseService;
import com.persagy.proxy.object.model.AdmObjectInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName AbstractAdmDictBaseServiceImpl
 * @Description: 字典查询
 * @Author linhuili
 * @Date 2021/8/31 18:21
 * @Version V1.0
 **/
@Slf4j
public class AbstractAdmDictBaseServiceImpl<T> implements IAdmDictBaseService<T> {

    @Autowired
    private DmpRwdClient rwdClient;

    @Autowired
    private DmpDicClient dicClient;

    /**
     * 查询DMP字典数据
     * @param context
     * @param dmpRequest
     * @param clazz
     * @return
     */
    @Override
    public AdmResponse doQueryDictData(InstanceUrlParam context,QueryCriteria dmpRequest, Class<T> clazz) {
        // 转换参数
        JSONObject para = null;
        try {
            para = JsonHelper.toJsonObject(dmpRequest);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            return null;
        }
        // 调用中台查询
        DmpResult<JSONArray> dmpResult = dicClient.queryDictData(context, para);
        List<AdmObjectType> admVOs = dictDataVOTransfer(dmpResult.getData());
        // 设置返回值
        AdmResponse response = AdmResponse.success(admVOs);
        Long total = dmpResult.getCount() == null ? null : dmpResult.getCount().longValue();
        response.setTotal(total);
        return response;
    }


    /**
     * 查询DMP对象类型
     * @param context
     * @param dmpRequest
     * @param clazz
     * @return
     */
    @Override
    public AdmResponse doQueryObjectType(InstanceUrlParam context,QueryCriteria dmpRequest, Class<T> clazz) {
        // 转换参数
        JSONObject para = null;
        try {
            para = JsonHelper.toJsonObject(dmpRequest);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            return null;
        }
        // 调用中台查询
        DmpResult<JSONArray> dmpResult = rwdClient.queryObjectType(context, para);
        JSONArray data = dmpResult.getData();
        List<AdmObjectType> admVOs = new ArrayList<>();
        if(CollUtil.isNotEmpty(data)){
            admVOs = data.toJavaList(AdmObjectType.class);
        }
        //参数格式转换
        dictDefTypeTransfer(admVOs);
        // 设置返回值
        AdmResponse response = AdmResponse.success(admVOs);
        Long total = dmpResult.getCount() == null ? null : dmpResult.getCount().longValue();
        response.setTotal(total);
        return response;
    }

    /**
     * 查询对象信息点
     * @param request
     * @return
     */
    @Override
    public AdmResponse doQueryObjectInfo(InstanceUrlParam context, AdmQueryCriteria request,String fieldName, Class<T> clazz) {
        // 转换为数据中台查询条件
        QueryCriteria dmpRequest = toDmpCriteria(request,fieldName);
        // 转换参数
        JSONObject para = null;
        try {
            para = JsonHelper.toJsonObject(dmpRequest);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            return null;
        }
        // 调用中台查询
        DmpResult<JSONArray> dmpResult = rwdClient.queryObjectInfo(context, para);
        List<AdmObjectInfo> admVOs = AdmEntityTransferUtil.toAdmMultiEntity(dmpResult.getData(), request.getProjection(), AdmObjectInfo.class);
        // BDTP信息点格式与ADM兼容处理
        handleObjectInfoResult(admVOs);
        // 设置返回值
        AdmResponse response = AdmResponse.success(admVOs);
        Long total = dmpResult.getCount() == null ? null : dmpResult.getCount().longValue();
        response.setTotal(total);
        response.setPageNumber(request.getPageNumber());
        response.setPageSize(request.getPageSize());
        return response;
    }

    /**
     * 修改
     * @param context
     * @param clazz
     * @param voList
     * @return
     */
    @Override
    public List<T> doUpdateObjectInfo(InstanceUrlParam context, Class<T> clazz, List<T> voList) {
        if(CollUtil.isEmpty(voList)) {
            return null;
        }
        ArrayNode vos = JsonNodeUtils.toArrayNode(voList, null, null);
        // 调用中台修改
        DmpResult<cn.hutool.json.JSONArray> response = rwdClient.batchUpdateObjectInfo(context, JSONArray.parseArray(vos.toString()));
        if(!DmpResult.SUCCESS.equals(response.getResult())) {
            throw new RuntimeException("调用中台查询接口出错：" + response.getMessage());
        }
        // 转换为结果
        return AdmEntityTransferUtil.toAdmMultiEntity(response.getData(), null, clazz);
    }

    /**
     * 删除信息点
     * @param context
     * @param voList
     * @return
     */
    @Override
    public void doDeleteObjectInfo(InstanceUrlParam context, List<T> voList) {
        if(CollUtil.isEmpty(voList)) {
            return;
        }
        List<String> idList = CollUtil.getFieldValues(voList, "id", String.class);
        // 调用中台修改
        DmpResult response = rwdClient.batchDeleteObjectInfo(context, idList);
        if(!DmpResult.SUCCESS.equals(response.getResult())) {
            throw new RuntimeException("调用中台查询接口出错：" + response.getMessage());
        }
    }

    /**
     * 信息点格式与ADM兼容处理
     * @param admVOs
     */
    private void handleObjectInfoResult(List<AdmObjectInfo> admVOs){
        if(CollUtil.isEmpty(admVOs)){
            return;
        }
        // 删除楼层的properties的信息点
        for (int i = admVOs.size() - 1; i >= 0; i--) {
            AdmObjectInfo admVo = admVOs.get(i);
            if ("floor".equals(admVo.getClassCode()) && "properties".equals(admVo.getCode())){
                admVo.setEditable(false);
            }
        }
        for (AdmObjectInfo admVO : admVOs) {
            admVO.setFirstName(admVO.getFirstTag());
            admVO.setSecondName(admVO.getSecondTag());
            admVO.setMultiple(admVO.getIsMultiple());
            admVO.setRegion(admVO.getIsRegion());
            admVO.setGroupCode(AppContext.getContext().getGroupCode());
            admVO.setSort(admVO.getShowOrder());

            //path路径处理
            handleObjectInfoPath(admVO);
            //信息点是否可见设置默认值
            if(admVO.getVisible() == null){
                admVO.setVisible(false);
            }
        }
    }
    /***
     * Description: 处理信息点的path
     * @param admVO : 信息点对象
     * @return : void
     * @author : lijie
     * @date :2021/11/3 13:29
     * Update By lijie 2021/11/3 13:29
     */
    private void handleObjectInfoPath(AdmObjectInfo admVO) {
        if(StrUtil.isNotBlank(admVO.getClassCode())
                && StrUtil.isNotBlank(admVO.getCode())
                && "height".equals(admVO.getCode())){
            // 特殊处理height信息点
            admVO.setPath(AdmDictConstant.INFOS_EX+admVO.getCode());
            return;
        }
        if (AdmDictConstant.TABLE_INFOS.contains(admVO.getCode())
                || ((AdmDictConstant.FIRST_BASE_TAG.equals(admVO.getFirstName())
                || AdmDictConstant.HIS_FIRST_BASE_TAG.equals(admVO.getFirstName())
                || AdmDictConstant.HIS_FIRST_BASE_TAG_TWO.equals(admVO.getFirstName()))
                && "pic".equals(admVO.getCode()))){
            // 1)表字段信息中包含的
            // 2)第一个名称为基本参数并且信息点为pic的
            admVO.setPath(admVO.getCode());
            return;
        }
        // 其余信息点带info.
        admVO.setPath(AdmDictConstant.INFOS_EX+admVO.getCode());
    }


    /**
     * 字典数据格式与ADM兼容
     * @param array
     */
    private List<AdmObjectType> dictDataVOTransfer(JSONArray array){
        List<AdmObjectType> result = new ArrayList<>();
        if(CollUtil.isEmpty(array)){
            return result;
        }
        ArrayNode dataNode = JsonNodeUtils.toArrayNode(array, null, null);
        for (JsonNode dicData : dataNode) {
            AdmObjectType objectType = new AdmObjectType();
            objectType.setCode(dicData.get("code").textValue());
            objectType.setName(dicData.get("label").textValue());
            objectType.setAliasCode(dicData.get("code").textValue());
            objectType.setAliasName(dicData.get("label").textValue());
            objectType.setObjType(dicData.get("type").textValue());

            result.add(objectType);
        }
        return result;
    }

    /**
     * 将ADM的查询条件转换为DMP的
     * 调用前注意：
     * - 调用前将name赋值，才会将条件中adm的属性替换为dmp的属性
     * - 统计查询时将isOnlyCount设置为true
     * 调用后注意（需要调用者自行处理的）：
     * - 不处理级联，级联应在调用者里处理级联调用转换后查询赋值
     * - 不处理projection，查询后自行根据projection筛选返回属性。（dmp只能指定扩展属性，而adm的是针对所有属性的）
     * @param admCriteria
     * @return
     */
    public static QueryCriteria toDmpCriteria(AdmQueryCriteria admCriteria,String fieldName) {
        QueryCriteria dmpCriteria = new QueryCriteria();
        // 拷贝分页
        AdmQueryCriteriaHelper.copyPageInfo(admCriteria, dmpCriteria);
        // 处理filters
        dmpCriteria.setCriteria(AdmQueryCriteriaHelper.toCriteria(admCriteria.getName(), admCriteria.getFilters()));
        if(StrUtil.isNotEmpty(admCriteria.getName())){
            // 处理name
            dmpCriteria.getCriteria().put(fieldName, admCriteria.getName());
        }
        dmpCriteria.getCriteria().put(AdmCommonConstant.VALID, ValidEnum.TRUE.getType());
        // 处理排序
        dmpCriteria.setOrders(AdmQueryCriteriaHelper.toOrderItem(admCriteria.getOrders()));
        // 处理统计
        dmpCriteria.setOnlyCount(admCriteria.isOnlyCount());
        return dmpCriteria;
    }


    /**
     * 字典类型返回结构与ADM兼容
     * @param data
     */
    private List<AdmObjectType> dictDefTypeTransfer(List<AdmObjectType> data){
        if(CollUtil.isEmpty(data)){
            return new ArrayList<>();
        }
        for (AdmObjectType datum : data) {
            String projectId = datum.getProjectId();
            String groupCode = datum.getGroupCode();
            if(StringUtils.isNotEmpty(groupCode) && !"0".equals(groupCode)){
                //集团级
                datum.setType("group");
            }else if(StringUtils.isNotEmpty(projectId) && !"0".equals(projectId)){
                //项目级
                datum.setType("project");
            }else{
                //平台级
                datum.setType("common");
            }
        }
        return data;
    }

    /**
     * 查询对象信息点
     * @param request
     * @return
     */
    @Override
    public AdmResponse doQueryObjectInfoCollect(InstanceUrlParam context, AdmQueryCriteria request,String fieldName, Class<T> clazz) {
        // 转换为数据中台查询条件
        QueryCriteria dmpRequest = toDmpCriteria(request,fieldName);
        // 转换参数
        JSONObject para = null;
        try {
            para = JsonHelper.toJsonObject(dmpRequest);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            return null;
        }
        // 调用中台查询
        log.info(para.toString());
        DmpResult<JSONArray> dmpResult = rwdClient.queryObjectInfoCollect(context, para);
        List<ObjectInfoCollect> admVOs = AdmEntityTransferUtil.toAdmMultiEntity(dmpResult.getData(), request.getProjection(), ObjectInfoCollect.class);
        // 设置返回值
        AdmResponse response = AdmResponse.success(admVOs);
        Long total = dmpResult.getCount() == null ? null : dmpResult.getCount().longValue();
        response.setTotal(total);
        response.setPageNumber(request.getPageNumber());
        response.setPageSize(request.getPageSize());
        return response;
    }

    /**
     * 设置采集信息
     * @param context
     * @param clazz
     * @param voList
     * @return
     */
    @Override
    public List<T> doSetObjectInfoCollect(InstanceUrlParam context, Class<T> clazz, List<T> voList) {
        if(CollUtil.isEmpty(voList)) {
            return null;
        }
        ArrayNode vos = JsonNodeUtils.toArrayNode(voList, null, null);
        // 调用中台修改
        DmpResult<cn.hutool.json.JSONArray> response = rwdClient.batchUpdateObjectInfoCollect(context, JSONArray.parseArray(vos.toString()));
        if(!DmpResult.SUCCESS.equals(response.getResult())) {
            throw new RuntimeException("调用中台查询接口出错：" + response.getMessage());
        }
        // 转换为结果
        return AdmEntityTransferUtil.toAdmMultiEntity(response.getData(), null, clazz);
    }

}
