package com.kym.entity.platform.response;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.annotation.JSONCreator;
import com.alibaba.fastjson2.annotation.JSONField;
import com.kym.entity.platform.PlatformPolicyInfo;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

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

/**
 * @author skyline
 * @description 设备策略信息
 * @date 2023-08-15 15:58
 */
@Data
@Slf4j
public class PlatformBusinessPolicy {
    /**
     * 业务策略查询流水号
     */
    @JSONField(name = "EquipBizSeq")
    private String equipBizSeq;

    public void setConnectorId(String connectorId) {
        this.connectorId = connectorId.replace("_", "");
    }

    /**
     * 充电设备接口编码
     */
    @JSONField(name = "ConnectorID")
    private String connectorId;
    /**
     * 操作结果
     * 0：失败
     * 1：成功
     */
    @JSONField(name = "SuccStat")
    private Integer succStat;
    /**
     * 失败原因
     * 0：无
     * 1：此充电桩业务策略不存在
     */
    @JSONField(name = "FailReason")
    private Integer failReason;
    /**
     * 时段数N 0~32
     */
    @JSONField(name = "SumPeriod")
    private Integer sumPeriod;
    /**
     * 单项业务策略信息
     */
    private List<PlatformPolicyInfo> policyInfos;

    @JSONCreator
    PlatformBusinessPolicy(@JSONField(name = "PolicyInfos") JSONArray array) {
        // 如果策略信息为空，不做转换（朗新新站点切换会出现此问题）
        if (array == null || array.isEmpty()) {
            policyInfos = null;
            return;
        }
        this.policyInfos = array.toJavaList(PlatformPolicyInfo.class);
        // 将尖峰平谷信息填入EnPolicyInfo中
        var elecPriceSet = policyInfos.stream().map(PlatformPolicyInfo::getElecPrice).collect(Collectors.toSet()).stream().sorted().toList();
        if (elecPriceSet.size() > 1) {
            // 平台数据错误时可能返回超过4档电价，记录原始价格并将相近的价格取低价作为标准，临时压缩到4档
            Map<Double, Double> priceStandardMap = new HashMap<>();
            var levelPrices = elecPriceSet;
            if (elecPriceSet.size() > PlatformPolicyInfo.PRICE_PERIOD.length) {
                log.error("业务策略电价档数异常，共{}档，原始电价列表：{}", elecPriceSet.size(), elecPriceSet);
                priceStandardMap = compressPriceToFourLevels(elecPriceSet);
                levelPrices = priceStandardMap.values().stream().distinct().sorted().toList();
                log.error("相近价格取低价压缩后电价列表：{}", levelPrices);
            }
            var finalLevelPrices = levelPrices;
            var finalPriceStandardMap = priceStandardMap;
            policyInfos = policyInfos.stream().peek(price -> {
                var standardPrice = finalPriceStandardMap.getOrDefault(price.getElecPrice(), price.getElecPrice());
                price.setElecPrice(standardPrice);
                price.setPricePeriod(PlatformPolicyInfo.PRICE_PERIOD[finalLevelPrices.indexOf(standardPrice)]);
            }).toList();
        } else {
            // 统一电价
            policyInfos = policyInfos.stream().peek(price -> price.setPricePeriod("统")).toList();
        }
    }

    /**
     * 价格档数超过4档时，反复合并价格最相近的两档（取低价为标准），压缩到4档
     *
     * @param prices 升序排列的电价列表
     * @return 原始电价 -> 标准电价 的映射
     */
    private static Map<Double, Double> compressPriceToFourLevels(List<Double> prices) {
        var priceStandardMap = new HashMap<Double, Double>();
        prices.forEach(price -> priceStandardMap.put(price, price));
        var levels = new ArrayList<>(prices);
        while (levels.size() > PlatformPolicyInfo.PRICE_PERIOD.length) {
            // 找出差值最小的相邻两档
            var mergeIndex = 0;
            var minGap = Double.MAX_VALUE;
            for (var i = 0; i < levels.size() - 1; i++) {
                var gap = levels.get(i + 1) - levels.get(i);
                if (gap < minGap) {
                    minGap = gap;
                    mergeIndex = i;
                }
            }
            // 取低价作为标准
            var standard = levels.get(mergeIndex);
            var merged = levels.remove(mergeIndex + 1);
            priceStandardMap.replaceAll((price, v) -> v.equals(merged) ? standard : v);
        }
        return priceStandardMap;
    }


}
