using CashLineERP.Domain.Common;
using CashLineERP.SharedKernel.Finance;

namespace CashLineERP.Domain.Finance;

public sealed class ReceiptReconciliationItem : Entity
{
    public long Id { get; private set; }

    public long ReceiptReconciliationRunId { get; private set; }

    public long BankStatementLineId { get; private set; }

    public long? AccountsReceivableReceiptId { get; private set; }

    public long? AccountsPayablePaymentId { get; private set; }

    public long? CustomerRefundId { get; private set; }

    public string MatchedDocumentType { get; private set; } = string.Empty;

    public string MatchStatusCode { get; private set; } = string.Empty;

    public decimal StatementAmount { get; private set; }

    public decimal? MatchedDocumentAmount { get; private set; }

    public decimal DifferenceAmount { get; private set; }

    public string? Notes { get; private set; }

    public string? ResolutionCode { get; private set; }

    public string? OverrideApprovalRoleCode { get; private set; }

    public string? OverrideReasonCode { get; private set; }

    public DateTime? ResolvedAtUtc { get; private set; }

    public long? ResolvedByUserId { get; private set; }

    public ReceiptReconciliationItem(
        long receiptReconciliationRunId,
        long bankStatementLineId,
        long? accountsReceivableReceiptId,
        long? accountsPayablePaymentId,
        long? customerRefundId,
        string matchedDocumentType,
        string matchStatusCode,
        decimal statementAmount,
        decimal? matchedDocumentAmount,
        decimal differenceAmount,
        string? notes)
    {
        ReceiptReconciliationRunId = receiptReconciliationRunId;
        BankStatementLineId = bankStatementLineId;
        AccountsReceivableReceiptId = accountsReceivableReceiptId;
        AccountsPayablePaymentId = accountsPayablePaymentId;
        CustomerRefundId = customerRefundId;
        MatchedDocumentType = matchedDocumentType;
        MatchStatusCode = matchStatusCode;
        StatementAmount = statementAmount;
        MatchedDocumentAmount = matchedDocumentAmount;
        DifferenceAmount = differenceAmount;
        Notes = notes;
    }

    private ReceiptReconciliationItem()
    {
    }

    public void ResolveWithAccountsReceivableReceipt(
        long actorUserId,
        long accountsReceivableReceiptId,
        decimal matchedDocumentAmount,
        string newStatusCode,
        string? notes)
    {
        AccountsReceivableReceiptId = accountsReceivableReceiptId;
        AccountsPayablePaymentId = null;
        CustomerRefundId = null;
        MatchedDocumentType = "AR_RECEIPT";
        MatchedDocumentAmount = matchedDocumentAmount;
        DifferenceAmount = StatementAmount - matchedDocumentAmount;
        ApplyResolution(actorUserId, newStatusCode, notes);
    }

    public void ResolveWithAccountsPayablePayment(
        long actorUserId,
        long accountsPayablePaymentId,
        decimal matchedDocumentAmount,
        string newStatusCode,
        string? notes)
    {
        AccountsReceivableReceiptId = null;
        AccountsPayablePaymentId = accountsPayablePaymentId;
        CustomerRefundId = null;
        MatchedDocumentType = "AP_PAYMENT";
        MatchedDocumentAmount = matchedDocumentAmount;
        DifferenceAmount = StatementAmount - matchedDocumentAmount;
        ApplyResolution(actorUserId, newStatusCode, notes);
    }

    public void ResolveWithCustomerRefund(
        long actorUserId,
        long customerRefundId,
        decimal matchedDocumentAmount,
        string newStatusCode,
        string? notes)
    {
        AccountsReceivableReceiptId = null;
        AccountsPayablePaymentId = null;
        CustomerRefundId = customerRefundId;
        MatchedDocumentType = "CUSTOMER_REFUND";
        MatchedDocumentAmount = matchedDocumentAmount;
        DifferenceAmount = StatementAmount - matchedDocumentAmount;
        ApplyResolution(actorUserId, newStatusCode, notes);
    }

    public void RecordOverrideApproval(string approvalRoleCode, string reasonCode)
    {
        ReconciliationOverrideCatalog.ValidateRoleReasonPair(approvalRoleCode, reasonCode);
        OverrideApprovalRoleCode = ReconciliationOverrideCatalog.NormalizeApprovalRoleCode(approvalRoleCode);
        OverrideReasonCode = ReconciliationOverrideCatalog.NormalizeReasonCode(reasonCode);
    }

    private void ApplyResolution(long actorUserId, string newStatusCode, string? notes)
    {
        MatchStatusCode = newStatusCode;
        ResolutionCode = newStatusCode;
        Notes = MergeNotes(notes);
        if (!string.Equals(newStatusCode, "OVERRIDDEN", StringComparison.OrdinalIgnoreCase))
        {
            OverrideApprovalRoleCode = null;
            OverrideReasonCode = null;
        }

        ResolvedAtUtc = DateTime.UtcNow;
        ResolvedByUserId = actorUserId;
        Touch(actorUserId);
    }

    private string? MergeNotes(string? notes)
    {
        if (string.IsNullOrWhiteSpace(Notes))
        {
            return notes;
        }

        if (string.IsNullOrWhiteSpace(notes))
        {
            return Notes;
        }

        return $"{Notes} | {notes}";
    }
}
