using System;
using System.Collections.Generic;
using StellaOps.Feedser.Storage.Mongo.Documents;

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

internal sealed record OracleDocumentMetadata(
    string AdvisoryId,
    string Title,
    DateTimeOffset Published,
    Uri DetailUri)
{
    private const string AdvisoryIdKey = "oracle.advisoryId";
    private const string TitleKey = "oracle.title";
    private const string PublishedKey = "oracle.published";

    public static IReadOnlyDictionary<string, string> CreateMetadata(string advisoryId, string title, DateTimeOffset published)
        => new Dictionary<string, string>(StringComparer.Ordinal)
        {
            [AdvisoryIdKey] = advisoryId,
            [TitleKey] = title,
            [PublishedKey] = published.ToString("O"),
        };

    public static OracleDocumentMetadata FromDocument(DocumentRecord document)
    {
        ArgumentNullException.ThrowIfNull(document);
        if (document.Metadata is null)
        {
            throw new InvalidOperationException("Oracle document metadata missing.");
        }

        var metadata = document.Metadata;
        if (!metadata.TryGetValue(AdvisoryIdKey, out var advisoryId) || string.IsNullOrWhiteSpace(advisoryId))
        {
            throw new InvalidOperationException("Oracle advisory id metadata missing.");
        }

        if (!metadata.TryGetValue(TitleKey, out var title) || string.IsNullOrWhiteSpace(title))
        {
            throw new InvalidOperationException("Oracle title metadata missing.");
        }

        if (!metadata.TryGetValue(PublishedKey, out var publishedRaw) || !DateTimeOffset.TryParse(publishedRaw, out var published))
        {
            throw new InvalidOperationException("Oracle published metadata invalid.");
        }

        if (!Uri.TryCreate(document.Uri, UriKind.Absolute, out var detailUri))
        {
            throw new InvalidOperationException("Oracle document URI invalid.");
        }

        return new OracleDocumentMetadata(advisoryId.Trim(), title.Trim(), published.ToUniversalTime(), detailUri);
    }
}
