using CashLineERP.Domain.Common;

namespace CashLineERP.Domain.Tax;

public sealed class EtaTransmissionAttempt : Entity
{
    public long Id { get; private set; }
    public long AccountsReceivableInvoiceId { get; private set; }
    public long EtaSubmissionLogId { get; private set; }
    public long IntegrationEndpointId { get; private set; }
    public string TransmissionNumber { get; private set; } = string.Empty;
    public string StatusCode { get; private set; } = "QUEUED";
    public string PayloadText { get; private set; } = string.Empty;
    public string? SignedPayloadText { get; private set; }
    public string? SignatureText { get; private set; }
    public string? AdapterReference { get; private set; }
    public string? ResponseText { get; private set; }
    public int AttemptNumber { get; private set; }
    public DateTime AvailableAtUtc { get; private set; }
    public DateTime? DispatchedAtUtc { get; private set; }
    public string? DispatchedByProcess { get; private set; }
    public DateTime? PolledAtUtc { get; private set; }
    public string? PolledByProcess { get; private set; }
    public string? LastErrorText { get; private set; }

    public EtaTransmissionAttempt(
        long accountsReceivableInvoiceId,
        long etaSubmissionLogId,
        long integrationEndpointId,
        string transmissionNumber,
        string payloadText,
        DateTime availableAtUtc)
    {
        if (accountsReceivableInvoiceId <= 0 || etaSubmissionLogId <= 0 || integrationEndpointId <= 0)
        {
            throw new InvalidOperationException("ETA transmission attempt requires valid invoice, submission, and endpoint identifiers.");
        }

        if (string.IsNullOrWhiteSpace(transmissionNumber))
        {
            throw new InvalidOperationException("ETA transmission number is required.");
        }

        if (string.IsNullOrWhiteSpace(payloadText))
        {
            throw new InvalidOperationException("ETA transmission payload is required.");
        }

        AccountsReceivableInvoiceId = accountsReceivableInvoiceId;
        EtaSubmissionLogId = etaSubmissionLogId;
        IntegrationEndpointId = integrationEndpointId;
        TransmissionNumber = transmissionNumber.Trim().ToUpperInvariant();
        PayloadText = payloadText;
        AvailableAtUtc = availableAtUtc;
    }

    private EtaTransmissionAttempt()
    {
    }

    public void Dispatch(string processorCode, string signatureText, string signedPayloadText, string adapterReference, string? responseText)
    {
        if (StatusCode != "QUEUED" && StatusCode != "RETRY")
        {
            throw new InvalidOperationException("Only queued or retry ETA transmissions can be dispatched.");
        }

        if (string.IsNullOrWhiteSpace(processorCode)
            || string.IsNullOrWhiteSpace(signatureText)
            || string.IsNullOrWhiteSpace(signedPayloadText)
            || string.IsNullOrWhiteSpace(adapterReference))
        {
            throw new InvalidOperationException("ETA transmission dispatch requires processor, signature, signed payload, and adapter reference.");
        }

        StatusCode = "DISPATCHED";
        SignatureText = signatureText.Trim();
        SignedPayloadText = signedPayloadText;
        AdapterReference = adapterReference.Trim().ToUpperInvariant();
        ResponseText = string.IsNullOrWhiteSpace(responseText) ? null : responseText.Trim();
        AttemptNumber += 1;
        DispatchedAtUtc = DateTime.UtcNow;
        DispatchedByProcess = processorCode.Trim().ToUpperInvariant();
        LastErrorText = null;
        Touch(null);
    }

    public void ScheduleRetry(string errorText, DateTime nextAttemptAtUtc)
    {
        if (string.IsNullOrWhiteSpace(errorText))
        {
            throw new InvalidOperationException("ETA transmission retry reason is required.");
        }

        StatusCode = "RETRY";
        LastErrorText = errorText.Trim();
        AvailableAtUtc = nextAttemptAtUtc;
        Touch(null);
    }

    public void PollAccepted(string processorCode, string etaUuid, string? responseText)
    {
        EnsurePollable(processorCode);

        if (string.IsNullOrWhiteSpace(etaUuid))
        {
            throw new InvalidOperationException("ETA acceptance polling requires ETA UUID.");
        }

        StatusCode = "ACCEPTED";
        ResponseText = string.IsNullOrWhiteSpace(responseText) ? null : responseText.Trim();
        LastErrorText = null;
        PolledAtUtc = DateTime.UtcNow;
        PolledByProcess = processorCode.Trim().ToUpperInvariant();
        Touch(null);
    }

    public void PollRejected(string processorCode, string errorText, string? responseText)
    {
        EnsurePollable(processorCode);

        if (string.IsNullOrWhiteSpace(errorText))
        {
            throw new InvalidOperationException("ETA rejection polling requires an error reason.");
        }

        StatusCode = "REJECTED";
        ResponseText = string.IsNullOrWhiteSpace(responseText) ? null : responseText.Trim();
        LastErrorText = errorText.Trim();
        PolledAtUtc = DateTime.UtcNow;
        PolledByProcess = processorCode.Trim().ToUpperInvariant();
        Touch(null);
    }

    private void EnsurePollable(string processorCode)
    {
        if (StatusCode != "DISPATCHED")
        {
            throw new InvalidOperationException("Only dispatched ETA transmissions can be polled.");
        }

        if (string.IsNullOrWhiteSpace(processorCode))
        {
            throw new InvalidOperationException("ETA transmission polling requires processor code.");
        }
    }

    public void MarkFailed(string errorText, string? responseText = null)
    {
        if (string.IsNullOrWhiteSpace(errorText))
        {
            throw new InvalidOperationException("ETA transmission failure reason is required.");
        }

        StatusCode = "FAILED";
        ResponseText = string.IsNullOrWhiteSpace(responseText) ? ResponseText : responseText.Trim();
        LastErrorText = errorText.Trim();
        Touch(null);
    }
}
