package com.jeesharp.platform.modules.web.starter.config;

import com.fasterxml.jackson.core.JsonParser;
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.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;

/**
 * 兼容多种字符串形态的 {@link LocalDateTime} 反序列化器。
 * <p>除管理端统一格式 {@code yyyy-MM-dd HH:mm:ss} 外，还须解析 OAuth2/Redis 等历史 ISO 串（含 {@code T}、微秒、时区偏移）。</p>
 *
 * @author jeesharp
 * @since 2026-06-06
 */
public class FlexibleLocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {

    private static final ZoneId DEFAULT_ZONE = ZoneId.of("Asia/Shanghai");

    private static final DateTimeFormatter STANDARD = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Override
    public Class<LocalDateTime> handledType() {
        return LocalDateTime.class;
    }

    @Override
    public LocalDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException {
        String text = parser.getText();
        if (text == null) {
            return null;
        }
        text = text.trim();
        if (text.isEmpty()) {
            return null;
        }

        LocalDateTime parsed = tryParse(text);
        if (parsed != null) {
            return parsed;
        }
        throw context.weirdStringException(text, LocalDateTime.class, "无法解析为 LocalDateTime");
    }

    private static LocalDateTime tryParse(String text) {
        try {
            return LocalDateTime.parse(text, STANDARD);
        } catch (DateTimeParseException ignored) {
            // continue
        }
        try {
            return LocalDateTime.parse(text, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
        } catch (DateTimeParseException ignored) {
            // continue
        }
        try {
            return OffsetDateTime.parse(text, DateTimeFormatter.ISO_OFFSET_DATE_TIME).toLocalDateTime();
        } catch (DateTimeParseException ignored) {
            // continue
        }
        try {
            return ZonedDateTime.parse(text, DateTimeFormatter.ISO_ZONED_DATE_TIME).toLocalDateTime();
        } catch (DateTimeParseException ignored) {
            // continue
        }
        try {
            return Instant.parse(text).atZone(DEFAULT_ZONE).toLocalDateTime();
        } catch (DateTimeParseException ignored) {
            return null;
        }
    }
}
