#nullable enable
using Baya.Domain.Common;

namespace Baya.Domain.Entities.Payments;

/// <summary>
/// The raw, deduplicated store of every inbound PSP/BNPL callback — the <b>idempotency chokepoint</b> of the
/// whole money path. PSP callbacks are at-least-once and retried, so the handler <b>upserts here first</b>,
/// keyed on <c>UNIQUE(provider_code, external_event_id)</c>, and <b>no-ops on a duplicate</b> inside the same
/// transaction that would mutate payment state: a replayed <c>succeeded</c> can never double-confirm and a
/// replayed <c>settled</c> can never double-count.
/// </summary>
public class PaymentWebhookEvent : BaseEntity<long>
{
    public string ProviderCode { get; set; } = null!;

    /// <summary>The provider's own event id — the second half of the idempotency key.</summary>
    public string ExternalEventId { get; set; } = null!;

    public string EventType { get; set; } = null!;

    /// <summary>Whether the signature verified. A false here forces <see cref="WebhookProcessingStatus.Ignored"/>
    /// and stops the path before any money moves.</summary>
    public bool SignatureValid { get; set; }

    public string PayloadJson { get; set; } = null!;

    /// <summary>Guarded — mutated only through the mark-* methods.</summary>
    public string ProcessingStatus { get; private set; } = WebhookProcessingStatus.Received;

    public long? RelatedPaymentTransactionId { get; private set; }

    public DateTime ReceivedAt { get; set; }
    public DateTime? ProcessedAt { get; private set; }

    public void MarkProcessed(long? relatedPaymentTransactionId, DateTime processedAt)
    {
        ProcessingStatus = WebhookProcessingStatus.Processed;
        RelatedPaymentTransactionId = relatedPaymentTransactionId;
        ProcessedAt = processedAt;
    }

    public void MarkIgnored(DateTime processedAt)
    {
        ProcessingStatus = WebhookProcessingStatus.Ignored;
        ProcessedAt = processedAt;
    }

    public void MarkFailed(DateTime processedAt)
    {
        ProcessingStatus = WebhookProcessingStatus.Failed;
        ProcessedAt = processedAt;
    }
}
