using System.Text.Json;
using System.Text.Json.Serialization;

namespace Web.Api.Common;

/// <summary>
/// DB 의 모든 DateTime 컬럼은 UTC 로 저장된다(Domain Entity 가 일관되게 DateTime.UtcNow 사용).
/// SQL Server datetime2 컬럼은 timezone 정보가 없어 EF Core 가 Kind = Unspecified 로 materialize 한다.
/// System.Text.Json 의 기본 동작은 Unspecified DateTime 을 Z/offset 없이 출력해서, 클라이언트 JS 가
/// 로컬 시간으로 오해 → 9시간(KST 오프셋) 차이 발생. 이 converter 가 Z 마커를 강제해서 문제를 해결.
/// </summary>
public sealed class UtcDateTimeConverter : JsonConverter<DateTime>
{
    public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var dt = reader.GetDateTime();

        return dt.Kind == DateTimeKind.Utc ? dt : DateTime.SpecifyKind(dt, DateTimeKind.Utc);
    }

    public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
    {
        var utc = value.Kind switch
        {
            DateTimeKind.Utc => value,
            DateTimeKind.Local => value.ToUniversalTime(),
            _ => DateTime.SpecifyKind(value, DateTimeKind.Utc)
        };

        writer.WriteStringValue(utc.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"));
    }
}

public sealed class UtcNullableDateTimeConverter : JsonConverter<DateTime?>
{
    private static readonly UtcDateTimeConverter Inner = new();

    public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TokenType == JsonTokenType.Null)
        {
            return null;
        }

        return Inner.Read(ref reader, typeof(DateTime), options);
    }

    public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options)
    {
        if (value is null)
        {
            writer.WriteNullValue();
            return;
        }

        Inner.Write(writer, value.Value, options);
    }
}