using System;
using System.Collections.Generic;
using MongoDB.Bson;

namespace StellaOps.Feedser.Storage.Mongo.ChangeHistory;

internal static class ChangeHistoryDocumentExtensions
{
    public static ChangeHistoryDocument ToDocument(this ChangeHistoryRecord record)
    {
        var changes = new List<BsonDocument>(record.Changes.Count);
        foreach (var change in record.Changes)
        {
            changes.Add(new BsonDocument
            {
                ["field"] = change.Field,
                ["type"] = change.ChangeType,
                ["previous"] = change.PreviousValue is null ? BsonNull.Value : new BsonString(change.PreviousValue),
                ["current"] = change.CurrentValue is null ? BsonNull.Value : new BsonString(change.CurrentValue),
            });
        }

        return new ChangeHistoryDocument
        {
            Id = record.Id.ToString(),
            SourceName = record.SourceName,
            AdvisoryKey = record.AdvisoryKey,
            DocumentId = record.DocumentId.ToString(),
            DocumentSha256 = record.DocumentSha256,
            CurrentHash = record.CurrentHash,
            PreviousHash = record.PreviousHash,
            CurrentSnapshot = record.CurrentSnapshot,
            PreviousSnapshot = record.PreviousSnapshot,
            Changes = changes,
            CapturedAt = record.CapturedAt.UtcDateTime,
        };
    }

    public static ChangeHistoryRecord ToRecord(this ChangeHistoryDocument document)
    {
        var changes = new List<ChangeHistoryFieldChange>(document.Changes.Count);
        foreach (var change in document.Changes)
        {
            var previousValue = change.TryGetValue("previous", out var previousBson) && previousBson is not BsonNull
                ? previousBson.AsString
                : null;
            var currentValue = change.TryGetValue("current", out var currentBson) && currentBson is not BsonNull
                ? currentBson.AsString
                : null;
            var fieldName = change.GetValue("field", "").AsString;
            var changeType = change.GetValue("type", "").AsString;
            changes.Add(new ChangeHistoryFieldChange(fieldName, changeType, previousValue, currentValue));
        }

        var capturedAtUtc = DateTime.SpecifyKind(document.CapturedAt, DateTimeKind.Utc);

        return new ChangeHistoryRecord(
            Guid.Parse(document.Id),
            document.SourceName,
            document.AdvisoryKey,
            Guid.Parse(document.DocumentId),
            document.DocumentSha256,
            document.CurrentHash,
            document.PreviousHash,
            document.CurrentSnapshot,
            document.PreviousSnapshot,
            changes,
            new DateTimeOffset(capturedAtUtc));
    }
}
