package com.gxwebsoft.common.core.config;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;

import java.io.IOException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

/**
 * LocalDateTime自定义反序列化器
 *
 * @author WebSoft
 * @since 2025-01-12
 */
public class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {

    private final DateTimeFormatter formatter;

    public LocalDateTimeDeserializer() {
        this(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }

    public LocalDateTimeDeserializer(DateTimeFormatter formatter) {
        this.formatter = formatter;
    }

    @Override
    public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        JsonToken t = p.currentToken();
        ZoneId zoneId = ctxt.getTimeZone() != null ? ctxt.getTimeZone().toZoneId() : ZoneId.systemDefault();

        // Accept epoch timestamps (seconds or millis) for compatibility with frontends that send numbers.
        if (t == JsonToken.VALUE_NUMBER_INT) {
            long ts = p.getLongValue();
            // Heuristic: 10+ digits is seconds; 13+ digits is millis (most common in JS).
            Instant instant = (String.valueOf(Math.abs(ts)).length() >= 13)
                    ? Instant.ofEpochMilli(ts)
                    : Instant.ofEpochSecond(ts);
            return LocalDateTime.ofInstant(instant, zoneId);
        }

        String value = p.getValueAsString();
        if (value == null || value.isEmpty()) {
            return null;
        }

        // Handle numeric timestamps passed as strings, e.g. "1769618486000"
        if (value.chars().allMatch(Character::isDigit)) {
            long ts = Long.parseLong(value);
            Instant instant = (value.length() >= 13) ? Instant.ofEpochMilli(ts) : Instant.ofEpochSecond(ts);
            return LocalDateTime.ofInstant(instant, zoneId);
        }

        return LocalDateTime.parse(value, formatter);
    }
}
