package com.usky.vpp.util;

import com.usky.vpp.config.VppUnProperties;
import com.usky.vpp.domain.VppResourcePoint;
import com.usky.vpp.domain.VppSite;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

/**
 * RegisterReport 量测点 rID 顺序索引（与 MetaDataReport 注册顺序一致）。
 */
public final class VppUnRegisterReportIndex {

    public enum Scope {
        VPP, SITE, RESOURCE
    }

    public static final class Entry {
        private final int rid;
        private final VppUnRegisterMetricDefinitions.RegisterMetric metric;
        private final Scope scope;
        private final VppSite site;
        private final VppResourcePoint resource;

        public Entry(int rid,
                     VppUnRegisterMetricDefinitions.RegisterMetric metric,
                     Scope scope,
                     VppSite site,
                     VppResourcePoint resource) {
            this.rid = rid;
            this.metric = metric;
            this.scope = scope;
            this.site = site;
            this.resource = resource;
        }

        public int getRid() {
            return rid;
        }

        public VppUnRegisterMetricDefinitions.RegisterMetric getMetric() {
            return metric;
        }

        public Scope getScope() {
            return scope;
        }

        public VppSite getSite() {
            return site;
        }

        public VppResourcePoint getResource() {
            return resource;
        }

        /** 曲线/实时数据计算时共用的有功功率量测定义（负荷预测与 VPP AP 相同）。 */
        public VppUnRegisterMetricDefinitions.RegisterMetric getDataMetric() {
            if (VppUnRegisterMetricDefinitions.isLoadForecast(metric)) {
                return VppUnRegisterMetricDefinitions.ACTIVE_POWER;
            }
            return metric;
        }
    }

    /** RegisterReport：虚拟电厂全部量测点。 */
    public static List<Entry> buildRegisterEntries(VppUnProperties properties,
                                                   List<VppSite> sites,
                                                   List<VppResourcePoint> resources,
                                                   Map<Long, String> deviceUnResourceIdMap) {
        return buildEntries(properties, sites, resources, deviceUnResourceIdMap, metric -> true);
    }

    /**
     * MomentData：虚拟电厂 8 项实时量测 + 站点/资源 AP。
     * 实时：AP、AP_E、AP_PE、上调/下调能力、响应时间、爬坡速度、持续时间。
     */
    public static List<Entry> buildMomentDataEntries(VppUnProperties properties,
                                                     List<VppSite> sites,
                                                     List<VppResourcePoint> resources,
                                                     Map<Long, String> deviceUnResourceIdMap) {
        return buildEntries(properties, sites, resources, deviceUnResourceIdMap,
                VppUnRegisterMetricDefinitions::isMomentMetric);
    }

    /**
     * IntervalData：虚拟电厂 9 项（基础 3 + 日前申报 5 + 负荷预测）+ 站点/资源 AP。
     */
    public static List<Entry> buildIntervalDataEntries(VppUnProperties properties,
                                                       List<VppSite> sites,
                                                       List<VppResourcePoint> resources,
                                                       Map<Long, String> deviceUnResourceIdMap) {
        return buildEntries(properties, sites, resources, deviceUnResourceIdMap,
                VppUnRegisterMetricDefinitions::isIntervalMetric);
    }

    @Deprecated
    public static List<Entry> buildEntries(VppUnProperties properties,
                                           List<VppSite> sites,
                                           List<VppResourcePoint> resources,
                                           Map<Long, String> deviceUnResourceIdMap) {
        return buildMomentDataEntries(properties, sites, resources, deviceUnResourceIdMap);
    }

    private static List<Entry> buildEntries(VppUnProperties properties,
                                            List<VppSite> sites,
                                            List<VppResourcePoint> resources,
                                            Map<Long, String> deviceUnResourceIdMap,
                                            Predicate<VppUnRegisterMetricDefinitions.RegisterMetric> vppMetricFilter) {
        List<Entry> entries = new ArrayList<>();
        int rid = 0;
        for (VppUnRegisterMetricDefinitions.RegisterMetric metric
                : VppUnRegisterMetricDefinitions.VPP_REGISTER_METRICS) {
            if (!vppMetricFilter.test(metric)) {
                rid++;
                continue;
            }
            entries.add(new Entry(rid++, metric, Scope.VPP, null, null));
        }
        appendSiteAndResourceEntries(entries, rid, sites, resources, deviceUnResourceIdMap);
        return entries;
    }

    private static void appendSiteAndResourceEntries(List<Entry> entries,
                                                     int rid,
                                                     List<VppSite> sites,
                                                     List<VppResourcePoint> resources,
                                                     Map<Long, String> deviceUnResourceIdMap) {
        if (sites != null) {
            for (VppSite site : sites) {
                if (site == null || !StringUtils.hasText(site.getUnResourceId())) {
                    continue;
                }
                entries.add(new Entry(rid++, VppUnRegisterMetricDefinitions.ACTIVE_POWER,
                        Scope.SITE, site, null));
            }
        }
        if (resources != null && deviceUnResourceIdMap != null) {
            for (VppResourcePoint resource : resources) {
                if (resource == null || resource.getDeviceId() == null) {
                    continue;
                }
                String resourceId = deviceUnResourceIdMap.get(resource.getDeviceId());
                if (!StringUtils.hasText(resourceId)) {
                    continue;
                }
                entries.add(new Entry(rid++, VppUnRegisterMetricDefinitions.ACTIVE_POWER,
                        Scope.RESOURCE, null, resource));
            }
        }
    }

    private VppUnRegisterReportIndex() {
    }
}
