package com.usky.vpp.util;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.usky.vpp.domain.VppCustomer;
import com.usky.vpp.domain.VppDrEvaluation;
import com.usky.vpp.domain.VppDrEvent;
import com.usky.vpp.domain.VppEnergySummaryDaily;
import com.usky.vpp.domain.VppReportRecord;
import com.usky.vpp.domain.VppReportTask;
import com.usky.vpp.domain.VppResourcePoint;
import com.usky.vpp.domain.VppSite;
import com.usky.vpp.service.vo.ReportPrefillVO;
import com.usky.vpp.service.vo.ReportValidateErrorVO;
import com.usky.vpp.service.vo.ReportValidateResultVO;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 监管信息报送工具
 */
public final class VppReportHelper {

    public static final int TASK_STATUS_PENDING_FILL = 0;
    public static final int TASK_STATUS_PENDING_AUDIT = 1;
    public static final int TASK_STATUS_SUBMITTING = 2;
    public static final int TASK_STATUS_COMPLETED = 3;
    public static final int TASK_STATUS_OVERDUE = 4;

    public static final int RECORD_STATUS_DRAFT = 0;
    public static final int RECORD_STATUS_PENDING_AUDIT = 1;
    public static final int RECORD_STATUS_SUBMITTING = 2;
    public static final int RECORD_STATUS_SUCCESS = 3;
    public static final int RECORD_STATUS_FAILED = 4;

    public static final int SUBMIT_MODE_API = 1;
    public static final int SUBMIT_MODE_MANUAL = 2;

    public static final int AUDIT_ACTION_SUBMIT = 1;
    public static final int AUDIT_ACTION_PASS = 2;
    public static final int AUDIT_ACTION_REJECT = 3;

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    private static final DateTimeFormatter RECORD_NO_FMT = DateTimeFormatter.ofPattern("yyyyMM");

    private VppReportHelper() {
    }

    public static String resolveReportOrgName(Integer reportOrg) {
        if (reportOrg == null) {
            return null;
        }
        switch (reportOrg) {
            case 1:
                return "交易中心";
            case 2:
                return "能监局";
            case 3:
                return "经信委";
            case 4:
                return "国网上海";
            default:
                return "未知机构";
        }
    }

    public static String nextRecordNo(String reportPeriod) {
        String period = StringUtils.hasText(reportPeriod) ? reportPeriod.replace("-", "") : RECORD_NO_FMT.format(LocalDate.now());
        return "REC-" + period + "-" + System.currentTimeMillis() % 1000;
    }

    public static String nextTaskNo() {
        return "RPT-" + RECORD_NO_FMT.format(LocalDate.now()) + "-" + System.currentTimeMillis() % 1000;
    }

    public static Map<String, Object> parseFormData(String json) {
        if (!StringUtils.hasText(json)) {
            return null;
        }
        try {
            return OBJECT_MAPPER.readValue(json, new TypeReference<Map<String, Object>>() {
            });
        } catch (Exception ex) {
            return null;
        }
    }

    public static String toJson(Object value) {
        if (value == null) {
            return null;
        }
        try {
            return OBJECT_MAPPER.writeValueAsString(value);
        } catch (Exception ex) {
            return null;
        }
    }

    public static List<Long> parseSiteIds(String json) {
        if (!StringUtils.hasText(json)) {
            return Collections.emptyList();
        }
        try {
            return OBJECT_MAPPER.readValue(json, new TypeReference<List<Long>>() {
            });
        } catch (Exception ex) {
            return Collections.emptyList();
        }
    }

    public static ReportPrefillVO buildPrefill(VppReportRecord record,
                                             VppReportTask task,
                                             List<VppCustomer> customers,
                                             List<VppResourcePoint> resources,
                                             List<VppSite> sites,
                                             List<VppEnergySummaryDaily> energyRows,
                                             List<VppDrEvent> drEvents,
                                             List<VppDrEvaluation> evaluations) {
        ReportPrefillVO prefill = new ReportPrefillVO();
        prefill.setReportPeriod(record.getReportPeriod());

        int customerCount = customers != null ? customers.size() : 0;
        prefill.setCustomerCount(customerCount);

        BigDecimal totalCapacity = BigDecimal.ZERO;
        int pvCount = 0;
        int essCount = 0;
        if (resources != null) {
            for (VppResourcePoint resource : resources) {
                if (resource.getCapacityKw() != null) {
                    totalCapacity = totalCapacity.add(resource.getCapacityKw());
                }
                if ("PV".equalsIgnoreCase(resource.getResourceType())) {
                    pvCount++;
                } else if ("ESS".equalsIgnoreCase(resource.getResourceType())) {
                    essCount++;
                }
            }
        }
        prefill.setTotalCapacityKw(totalCapacity);

        BigDecimal totalGen = BigDecimal.ZERO;
        BigDecimal totalUse = BigDecimal.ZERO;
        if (energyRows != null) {
            for (VppEnergySummaryDaily row : energyRows) {
                if (row.getGenEnergyKwh() != null) {
                    totalGen = totalGen.add(row.getGenEnergyKwh());
                }
                if (row.getUseEnergyKwh() != null) {
                    totalUse = totalUse.add(row.getUseEnergyKwh());
                }
            }
        }
        prefill.setTotalGenKwh(totalGen);
        prefill.setTotalUseKwh(totalUse);
        prefill.setDrEventCount(drEvents != null ? drEvents.size() : 0);

        BigDecimal drSubsidy = BigDecimal.ZERO;
        if (evaluations != null) {
            for (VppDrEvaluation evaluation : evaluations) {
                if (evaluation.getSubsidyAmount() != null) {
                    drSubsidy = drSubsidy.add(evaluation.getSubsidyAmount());
                }
            }
        }
        prefill.setDrTotalSubsidy(drSubsidy);

        String vppName = resolveVppName(sites, customers, task);
        Map<String, Object> formData = new LinkedHashMap<>();
        Map<String, Object> basicInfo = new LinkedHashMap<>();
        basicInfo.put("vppName", vppName);
        basicInfo.put("reportMonth", record.getReportPeriod());
        formData.put("basicInfo", basicInfo);

        Map<String, Object> resourceStats = new LinkedHashMap<>();
        resourceStats.put("pvCount", pvCount);
        resourceStats.put("essCount", essCount);
        resourceStats.put("totalCapacityKw", totalCapacity);
        formData.put("resourceStats", resourceStats);

        Map<String, Object> energyData = new LinkedHashMap<>();
        energyData.put("genKwh", totalGen);
        energyData.put("useKwh", totalUse);
        formData.put("energyData", energyData);

        Map<String, Object> drData = new LinkedHashMap<>();
        drData.put("eventCount", prefill.getDrEventCount());
        drData.put("totalSubsidy", drSubsidy);
        formData.put("drData", drData);

        prefill.setFormData(formData);
        return prefill;
    }

    public static ReportValidateResultVO validateFormData(Map<String, Object> formData,
                                                          int systemPvCount,
                                                          boolean strict) {
        ReportValidateResultVO result = new ReportValidateResultVO();
        List<ReportValidateErrorVO> errors = new ArrayList<>();
        if (formData == null || formData.isEmpty()) {
            errors.add(new ReportValidateErrorVO("formData", "填报数据不能为空"));
            result.setValid(false);
            result.setErrors(errors);
            return result;
        }

        JsonNode root = OBJECT_MAPPER.valueToTree(formData);
        JsonNode basicInfo = root.path("basicInfo");
        if (strict) {
            if (!StringUtils.hasText(basicInfo.path("vppName").asText(null))) {
                errors.add(new ReportValidateErrorVO("basicInfo.vppName", "虚拟电厂名称不能为空"));
            }
            if (!StringUtils.hasText(basicInfo.path("reportMonth").asText(null))) {
                errors.add(new ReportValidateErrorVO("basicInfo.reportMonth", "报送月份不能为空"));
            }
        }

        JsonNode energyData = root.path("energyData");
        BigDecimal genKwh = readDecimal(energyData.path("genKwh"));
        BigDecimal useKwh = readDecimal(energyData.path("useKwh"));
        if (genKwh != null && genKwh.compareTo(BigDecimal.ZERO) < 0) {
            errors.add(new ReportValidateErrorVO("energyData.genKwh", "发电量不能为负数"));
        }
        if (useKwh != null && useKwh.compareTo(BigDecimal.ZERO) < 0) {
            errors.add(new ReportValidateErrorVO("energyData.useKwh", "用电量不能为负数"));
        }

        JsonNode resourceStats = root.path("resourceStats");
        if (resourceStats.has("pvCount") && !resourceStats.path("pvCount").isNull()) {
            int formPvCount = resourceStats.path("pvCount").asInt(-1);
            if (formPvCount >= 0 && formPvCount != systemPvCount) {
                errors.add(new ReportValidateErrorVO("resourceStats.pvCount", "光伏数量与系统统计不一致"));
            }
        }

        result.setErrors(errors);
        result.setValid(errors.isEmpty());
        return result;
    }

    public static PeriodRange parseReportPeriod(String reportPeriod) {
        if (!StringUtils.hasText(reportPeriod)) {
            return null;
        }
        try {
            YearMonth yearMonth = YearMonth.parse(reportPeriod, DateTimeFormatter.ofPattern("yyyy-MM"));
            return new PeriodRange(yearMonth.atDay(1), yearMonth.atEndOfMonth());
        } catch (DateTimeParseException ex) {
            return null;
        }
    }

    private static String resolveVppName(List<VppSite> sites, List<VppCustomer> customers, VppReportTask task) {
        if (sites != null) {
            for (VppSite site : sites) {
                if (StringUtils.hasText(site.getOwnerName())) {
                    return site.getOwnerName();
                }
            }
        }
        if (customers != null && customers.size() == 1) {
            String name = customers.get(0).getCustomerName();
            if (StringUtils.hasText(name)) {
                return name;
            }
        }
        if (task != null && StringUtils.hasText(task.getTaskName())) {
            return task.getTaskName();
        }
        return "虚拟电厂";
    }

    private static BigDecimal readDecimal(JsonNode node) {
        if (node == null || node.isNull() || node.isMissingNode()) {
            return null;
        }
        if (node.isNumber()) {
            return node.decimalValue();
        }
        String text = node.asText(null);
        if (!StringUtils.hasText(text)) {
            return null;
        }
        try {
            return new BigDecimal(text);
        } catch (NumberFormatException ex) {
            return null;
        }
    }

    public static final class PeriodRange {
        private final LocalDate start;
        private final LocalDate end;

        public PeriodRange(LocalDate start, LocalDate end) {
            this.start = start;
            this.end = end;
        }

        public LocalDate getStart() {
            return start;
        }

        public LocalDate getEnd() {
            return end;
        }
    }
}
