package com.usky.vpp.util;

import com.usky.vpp.constant.VppDrEventStatus;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Map;

/**
 * 运管平台 UN 报文解析辅助（兼容多种字段命名与嵌套结构）
 */
public final class VppUnPayloadHelper {

    private static final DateTimeFormatter[] DATE_TIME_FORMATTERS = {
            DateTimeFormatter.ISO_LOCAL_DATE_TIME,
            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"),
            DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS"),
            DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss")
    };

    private VppUnPayloadHelper() {
    }

    public static Map<String, Object> unwrapInvitationPayload(Map<String, Object> body) {
        return unwrap(body, "event", "eventInfo", "eventData", "invitation", "data");
    }

    public static Map<String, Object> unwrapOptPayload(Map<String, Object> body) {
        Map<String, Object> nested = unwrap(body, "opt", "optInfo", "optRequest", "event", "eventInfo", "data");
        return nested != null ? nested : body;
    }

    public static Map<String, Object> unwrapClearingPayload(Map<String, Object> body) {
        return unwrap(body, "cq", "cqInfo", "cqRequest", "clearing", "clearingInfo", "event", "data");
    }

    @SuppressWarnings("unchecked")
    private static Map<String, Object> unwrap(Map<String, Object> body, String... nestedKeys) {
        if (body == null || body.isEmpty()) {
            return body;
        }
        for (String key : nestedKeys) {
            Object nested = body.get(key);
            if (nested instanceof Map) {
                return (Map<String, Object>) nested;
            }
        }
        return body;
    }

    public static boolean hasInvitationFields(Map<String, Object> payload) {
        if (payload == null) {
            return false;
        }
        if (payload.containsKey("events") || payload.containsKey("descriptor")) {
            return true;
        }
        return getDateTime(payload, "startTime", "start_time", "dtstart", "beginTime") != null
                || getDecimal(payload, "targetCapacityKw", "target_capacity_kw", "targetKw", "capacity", "targetCapacity") != null;
    }

    public static Boolean getBoolean(Map<String, Object> map, String... keys) {
        Object value = getValue(map, keys);
        if (value == null) {
            return null;
        }
        if (value instanceof Boolean) {
            return (Boolean) value;
        }
        String text = String.valueOf(value).trim().toLowerCase();
        if ("true".equals(text) || "1".equals(text)) {
            return true;
        }
        if ("false".equals(text) || "0".equals(text)) {
            return false;
        }
        return null;
    }

    public static String getString(Map<String, Object> map, String... keys) {
        Object value = getValue(map, keys);
        if (value == null) {
            return null;
        }
        String text = String.valueOf(value).trim();
        return StringUtils.hasText(text) ? text : null;
    }

    public static Integer getInteger(Map<String, Object> map, String... keys) {
        Object value = getValue(map, keys);
        if (value == null) {
            return null;
        }
        if (value instanceof Number) {
            return ((Number) value).intValue();
        }
        String text = String.valueOf(value).trim();
        if (!StringUtils.hasText(text)) {
            return null;
        }
        try {
            return Integer.parseInt(text);
        } catch (NumberFormatException ex) {
            return null;
        }
    }

    public static Object getRaw(Map<String, Object> map, String... keys) {
        return getValue(map, keys);
    }

    public static BigDecimal getDecimal(Map<String, Object> map, String... keys) {
        Object value = getValue(map, keys);
        if (value == null) {
            return null;
        }
        if (value instanceof BigDecimal) {
            return (BigDecimal) value;
        }
        if (value instanceof Number) {
            return BigDecimal.valueOf(((Number) value).doubleValue());
        }
        String text = String.valueOf(value).trim();
        if (!StringUtils.hasText(text)) {
            return null;
        }
        try {
            return new BigDecimal(text);
        } catch (NumberFormatException ex) {
            return null;
        }
    }

    public static LocalDateTime getDateTime(Map<String, Object> map, String... keys) {
        Object value = getValue(map, keys);
        if (value == null) {
            return null;
        }
        if (value instanceof LocalDateTime) {
            return (LocalDateTime) value;
        }
        if (value instanceof Number) {
            long epoch = ((Number) value).longValue();
            if (String.valueOf(epoch).length() <= 10) {
                epoch *= 1000;
            }
            return LocalDateTime.ofInstant(Instant.ofEpochMilli(epoch), ZoneId.systemDefault());
        }
        String text = String.valueOf(value).trim();
        if (!StringUtils.hasText(text)) {
            return null;
        }
        for (DateTimeFormatter formatter : DATE_TIME_FORMATTERS) {
            try {
                return LocalDateTime.parse(text, formatter);
            } catch (DateTimeParseException ignored) {
                // try next pattern
            }
        }
        return null;
    }

    public static Integer parseResponseType(Object raw) {
        if (raw == null) {
            return null;
        }
        if (raw instanceof Number) {
            int value = ((Number) raw).intValue();
            return value >= 1 && value <= 3 ? value : null;
        }
        String text = String.valueOf(raw).trim().toUpperCase();
        if (text.contains("日前") || "DAY_AHEAD".equals(text) || "1".equals(text)) {
            return 1;
        }
        if (text.contains("日内") || "INTRADAY".equals(text) || "2".equals(text)) {
            return 2;
        }
        if (text.contains("秒") || "REALTIME".equals(text) || "3".equals(text)) {
            return 3;
        }
        return null;
    }

    public static Integer parseEventType(Object raw) {
        if (raw == null) {
            return null;
        }
        if (raw instanceof Number) {
            int value = ((Number) raw).intValue();
            return value >= 1 && value <= 2 ? value : null;
        }
        String text = String.valueOf(raw).trim().toUpperCase();
        if (text.contains("削峰") || "PEAK".equals(text) || "1".equals(text)) {
            return 1;
        }
        if (text.contains("填谷") || "VALLEY".equals(text) || "FILLVALLEY".equals(text) || "2".equals(text)) {
            return 2;
        }
        return null;
    }

    public static boolean isCancelled(Map<String, Object> payload) {
        Integer status = getInteger(payload, "eventStatus", "event_status", "status");
        if (status != null && (status == 4 || status == VppDrEventStatus.CANCELLED)) {
            return true;
        }
        String text = getString(payload, "eventStatus", "event_status", "status", "eventState");
        if (!StringUtils.hasText(text)) {
            return false;
        }
        text = text.trim().toUpperCase();
        return text.contains("取消") || "CANCELLED".equals(text) || "CANCELED".equals(text)
                || "4".equals(text) || "5".equals(text);
    }

    private static Object getValue(Map<String, Object> map, String... keys) {
        if (map == null) {
            return null;
        }
        for (String key : keys) {
            if (map.containsKey(key) && map.get(key) != null) {
                return map.get(key);
            }
        }
        return null;
    }
}
