package com.purui.prims.headless.server.utils;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.purui.prims.common.pojo.DataFormat;
import com.purui.prims.common.pojo.enums.DataFormatTypeEnum;
import com.purui.prims.common.pojo.enums.PublishEnum;
import com.purui.prims.common.pojo.enums.StatusEnum;
import com.purui.prims.common.pojo.enums.TypeEnums;
import com.purui.prims.common.util.BeanMapper;
import com.purui.prims.common.util.ContextUtils;
import com.purui.prims.headless.api.pojo.MetricDefineByFieldParams;
import com.purui.prims.headless.api.pojo.MetricDefineByMeasureParams;
import com.purui.prims.headless.api.pojo.MetricDefineByMetricParams;
import com.purui.prims.headless.api.pojo.RelateDimension;
import com.purui.prims.headless.api.pojo.enums.MetricDefineType;
import com.purui.prims.headless.api.pojo.enums.MetricType;
import com.purui.prims.headless.api.pojo.request.MetricReq;
import com.purui.prims.headless.api.pojo.response.BizConditionResp;
import com.purui.prims.headless.api.pojo.response.DataSetResp;
import com.purui.prims.headless.api.pojo.response.DimensionResp;
import com.purui.prims.headless.api.pojo.response.MetricResp;
import com.purui.prims.headless.api.pojo.response.ModelResp;
import com.purui.prims.headless.server.persistence.dataobject.MetricDO;
import com.purui.prims.headless.server.persistence.dataobject.StatisticsPeriodDO;
import com.purui.prims.headless.server.service.BizConditionService;
import com.purui.prims.headless.server.service.DimensionService;
import com.purui.prims.headless.server.service.StatisticsPeriodService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 指标对象转换类
 *
 * @author charlie
 * @date 2024/7/5
 */
public class MetricConverter {

    public static MetricDO convert2MetricDO(MetricReq metricReq) {
        MetricDO metricDO = new MetricDO();
        if (metricReq.getDataFormat() == null) {
            metricReq.setDataFormat(new DataFormat());
        }
        BeanMapper.mapper(metricReq, metricDO);
        metricDO.setType(metricReq.getMetricType().name());
        metricDO.setTypeParams(metricReq.getTypeParamsJson());
        metricDO.setDataFormat(JSONObject.toJSONString(metricReq.getDataFormat()));
        metricDO.setDataFormatType(metricReq.getDataFormatType());
        metricDO.setClassifications(metricReq.getClassifications());
        metricDO.setRelateDimensions(JSONObject.toJSONString(metricReq.getRelateDimension()));
        metricDO.setStatus(StatusEnum.ONLINE.getCode());
        metricDO.setIsPublish(PublishEnum.UN_PUBLISHED.getCode());
        if (metricReq.getExt() != null) {
            metricDO.setExt(JSONObject.toJSONString(metricReq.getExt()));
        }
        metricDO.setDefineType(metricReq.getMetricDefineType().name());
        return metricDO;
    }

    public static MetricDO convert(MetricDO metricDO, MetricReq metricReq) {
        BeanMapper.mapper(metricReq, metricDO);
        metricDO.setType(metricReq.getMetricType().name());
        metricDO.setDefineType(metricReq.getMetricDefineType().name());
        metricDO.setDataFormatType(metricReq.getDataFormatType());
        if (metricReq.getDataFormat() != null) {
            metricDO.setDataFormat(JSONObject.toJSONString(metricReq.getDataFormat()));
        }
        if (metricReq.getRelateDimension() != null) {
            metricDO.setRelateDimensions(JSONObject.toJSONString(metricReq.getRelateDimension()));
        }
        if (metricReq.getClassifications() != null) {
            metricDO.setClassifications(metricReq.getClassifications());
        }
        if (metricReq.getExt() != null) {
            metricDO.setExt(JSONObject.toJSONString(metricReq.getExt()));
        }
        if (metricReq.getTypeParamsJson() != null) {
            metricDO.setTypeParams(metricReq.getTypeParamsJson());
        }
        return metricDO;
    }

    public static MetricResp convert2MetricResp(MetricDO metricDO) {
        return convert2MetricResp(metricDO, new HashMap<>(), Lists.newArrayList());
    }

    public static MetricResp convert2MetricResp(MetricDO metricDO, Map<Long, ModelResp> modelMap, List<Long> collect) {
        MetricResp metricResp = new MetricResp();
        BeanUtils.copyProperties(metricDO, metricResp);

        metricResp.setDataFormat(JSONObject.parseObject(metricDO.getDataFormat(), DataFormat.class));
        if (StringUtils.isNotEmpty(metricDO.getDataFormatType())) {
            metricResp.setDataFormatType(DataFormatTypeEnum.valueOf(metricDO.getDataFormatType().toUpperCase(Locale.ROOT)));
        }
        ModelResp modelResp = modelMap.get(metricDO.getModelId());
        if (modelResp != null) {
            metricResp.setModelName(modelResp.getName());
            metricResp.setModelBizName(modelResp.getBizName());
            metricResp.setDomainId(modelResp.getDomainId());
            metricResp.setDomainName(modelResp.getDomainName());
        }
        metricResp.setIsCollect(collect != null && collect.contains(metricDO.getId()));
        metricResp.setClassifications(metricDO.getClassifications());
        metricResp.setRelateDimension(JSONObject.parseObject(metricDO.getRelateDimensions(),
            RelateDimension.class));
        if (metricDO.getExt() != null) {
            metricResp.setExt(JSONObject.parseObject(metricDO.getExt(), HashMap.class));
        }
        if (MetricDefineType.MEASURE.name().equalsIgnoreCase(metricDO.getDefineType())) {
            metricResp.setMetricDefineByMeasureParams(JSONObject.parseObject(metricDO.getTypeParams(),
                MetricDefineByMeasureParams.class));
        } else if (MetricDefineType.METRIC.name().equalsIgnoreCase(metricDO.getDefineType())) {
            metricResp.setMetricDefineByMetricParams(JSONObject.parseObject(metricDO.getTypeParams(),
                MetricDefineByMetricParams.class));
        } else if (MetricDefineType.CUSTOM.name().equalsIgnoreCase(metricDO.getDefineType())) {
            metricResp.setMetricDefineByFieldParams(JSONObject.parseObject(metricDO.getTypeParams(),
                MetricDefineByFieldParams.class));
        }
        if (metricDO.getDefineType() != null) {
            metricResp.setMetricDefineType(MetricDefineType.valueOf(metricDO.getDefineType()));
        }
        if (StringUtils.isEmpty(metricResp.getType())) {
            metricResp.setType(getMetricType(metricResp.getMetricDefineType(), metricResp.getMetricDefineByMeasureParams()).name());
        }
        metricResp.setTypeEnum(TypeEnums.METRIC);
        // 业务限定
        if (metricDO.getConditionId() != null) {
            BizConditionService bizConditionService = ContextUtils.getBean(BizConditionService.class);
            BizConditionResp bizCondition = bizConditionService.getCondition(metricDO.getConditionId());
            metricResp.setBizConditionResp(bizCondition);
        }
        // 时间维度
        if (metricDO.getDateDimId() != null) {
            DimensionService dimensionService = ContextUtils.getBean(DimensionService.class);
            DimensionResp dimensionResp = dimensionService.getDimension(metricDO.getDateDimId());
            metricResp.setDateDimensionResp(dimensionResp);
        }
        // 统计周期
        if (metricDO.getPeriodId() != null) {
            StatisticsPeriodService periodService = ContextUtils.getBean(StatisticsPeriodService.class);
            StatisticsPeriodDO periodDO = periodService.getById(metricDO.getPeriodId());
            if (periodDO != null) {
                metricResp.setStatisticsPeriod(periodDO.getCode());
            }
        }
        metricResp.setDefaultAgg(metricDO.getOperations());
        return metricResp;
    }

    public static List<MetricResp> filterByDataSet(List<MetricResp> metricResps, DataSetResp dataSetResp) {
        return metricResps.stream().filter(metricResp ->
                              dataSetResp.metricIds().contains(metricResp.getId())
                              || dataSetResp.getAllIncludeAllModels().contains(metricResp.getModelId()))
                          .collect(Collectors.toList());
    }

    // 获取指标类型
    private static MetricType getMetricType(MetricDefineType metricDefineType, MetricDefineByMeasureParams metricDefineByMeasureParams) {
        if (MetricType.isComposite(metricDefineType)) {
            return MetricType.COMPOSITE;
        }
        if (MetricType.isDerived(metricDefineType, metricDefineByMeasureParams)) {
            return MetricType.DERIVED;
        }
        return MetricType.ATOMIC;
    }

}
