using System;
using MongoDB.Bson;
using StellaOps.Feedser.Storage.Mongo.Documents;

namespace StellaOps.Feedser.Source.Vndr.Vmware.Internal;

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

    public BsonDocument ToBsonDocument()
    {
        var document = new BsonDocument
        {
            ["sha256"] = Sha256 ?? string.Empty,
        };

        if (!string.IsNullOrWhiteSpace(ETag))
        {
            document["etag"] = ETag;
        }

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

        return document;
    }

    public static VmwareFetchCacheEntry FromBson(BsonDocument document)
    {
        var sha256 = document.TryGetValue("sha256", out var shaValue) ? shaValue.ToString() : string.Empty;
        string? etag = null;
        if (document.TryGetValue("etag", out var etagValue) && !etagValue.IsBsonNull)
        {
            etag = etagValue.ToString();
        }

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

        return new VmwareFetchCacheEntry(sha256, etag, lastModified);
    }

    public static VmwareFetchCacheEntry FromDocument(DocumentRecord document)
    {
        ArgumentNullException.ThrowIfNull(document);

        return new VmwareFetchCacheEntry(
            document.Sha256,
            document.Etag,
            document.LastModified?.ToUniversalTime());
    }

    public bool Matches(DocumentRecord document)
    {
        ArgumentNullException.ThrowIfNull(document);

        if (!string.IsNullOrEmpty(Sha256) && !string.IsNullOrEmpty(document.Sha256)
            && string.Equals(Sha256, document.Sha256, StringComparison.OrdinalIgnoreCase))
        {
            return true;
        }

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

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

        return false;
    }
}
