using System;
using MongoDB.Bson;

namespace StellaOps.Feedser.Source.Distro.Ubuntu.Internal;

internal sealed record UbuntuFetchCacheEntry(string? ETag, DateTimeOffset? LastModified)
{
    public static UbuntuFetchCacheEntry Empty { get; } = new(null, null);

    public static UbuntuFetchCacheEntry FromDocument(StellaOps.Feedser.Storage.Mongo.Documents.DocumentRecord document)
        => new(document.Etag, document.LastModified);

    public static UbuntuFetchCacheEntry FromBson(BsonDocument document)
    {
        if (document is null || document.ElementCount == 0)
        {
            return Empty;
        }

        string? etag = null;
        DateTimeOffset? lastModified = null;

        if (document.TryGetValue("etag", out var etagValue) && etagValue.BsonType == BsonType.String)
        {
            etag = etagValue.AsString;
        }

        if (document.TryGetValue("lastModified", out var modifiedValue))
        {
            lastModified = modifiedValue.BsonType switch
            {
                BsonType.DateTime => DateTime.SpecifyKind(modifiedValue.ToUniversalTime(), DateTimeKind.Utc),
                BsonType.String when DateTimeOffset.TryParse(modifiedValue.AsString, out var parsed) => parsed.ToUniversalTime(),
                _ => null
            };
        }

        return new UbuntuFetchCacheEntry(etag, lastModified);
    }

    public BsonDocument ToBsonDocument()
    {
        var doc = new BsonDocument();
        if (!string.IsNullOrWhiteSpace(ETag))
        {
            doc["etag"] = ETag;
        }

        if (LastModified.HasValue)
        {
            doc["lastModified"] = LastModified.Value.UtcDateTime;
        }

        return doc;
    }

    public bool Matches(StellaOps.Feedser.Storage.Mongo.Documents.DocumentRecord document)
    {
        if (document is null)
        {
            return false;
        }

        if (!string.Equals(ETag, document.Etag, StringComparison.Ordinal))
        {
            return false;
        }

        if (LastModified.HasValue && document.LastModified.HasValue)
        {
            return LastModified.Value.UtcDateTime == document.LastModified.Value.UtcDateTime;
        }

        return !LastModified.HasValue && !document.LastModified.HasValue;
    }
}
