namespace Books.Api.Invoicing.Services;

/// <summary>
/// Unified service for posting sales documents (invoices and credit notes) to the Ledger.
/// Both document types use the same posting logic, just with opposite entry directions:
/// - Invoice: Debit Customer, Credit Revenue, Credit VAT
/// - Credit Note: Credit Customer, Debit Revenue, Debit VAT
/// </summary>
public interface IDocumentPostingService
{
    /// <summary>
    /// Posts a sales document (invoice or credit note) to the Ledger.
    /// </summary>
    Task<PostingResult> PostSalesDocumentAsync(SalesDocumentPostingRequest request, CancellationToken ct = default);

    /// <summary>
    /// Reverses a previously posted sales document.
    /// </summary>
    Task<PostingResult> ReverseSalesDocumentAsync(
        string documentId,
        string originalTransactionId,
        string reason,
        CancellationToken ct = default);

    /// <summary>
    /// Posts a payment against a customer sub-ledger account.
    /// </summary>
    Task<PostingResult> PostPaymentAsync(PaymentPostingRequest request, CancellationToken ct = default);
}

/// <summary>
/// Type of sales document - determines the direction of ledger entries.
/// </summary>
public enum SalesDocumentType
{
    /// <summary>
    /// Invoice: Debit Customer, Credit Revenue, Credit VAT
    /// </summary>
    Invoice = 1,

    /// <summary>
    /// Credit Note: Credit Customer, Debit Revenue, Debit VAT (opposite of invoice)
    /// </summary>
    CreditNote = -1
}

/// <summary>
/// Request to post a sales document to the ledger.
/// </summary>
public record SalesDocumentPostingRequest(
    string DocumentId,
    SalesDocumentType DocumentType,
    string CustomerId,
    string CompanyId,
    string? FiscalYearId,
    string DocumentNumber,
    IReadOnlyList<SalesLineItem> Lines,
    string? DefaultRevenueAccountId,
    string? Description = null
);

/// <summary>
/// A line item for sales document posting.
/// </summary>
public record SalesLineItem(
    decimal AmountExVat,
    decimal AmountVat,
    decimal AmountTotal,
    string? AccountId
);

/// <summary>
/// Request to post a payment.
/// </summary>
public record PaymentPostingRequest(
    string DocumentId,
    string CustomerId,
    string BankAccountId,
    decimal Amount,
    string? FiscalYearId,
    string? Reference = null
);

/// <summary>
/// Result of a posting operation.
/// </summary>
public record PostingResult
{
    public bool Success { get; init; }
    public string? TransactionId { get; init; }
    public string? ErrorCode { get; init; }
    public string? ErrorMessage { get; init; }

    public static PostingResult Succeeded(string transactionId) =>
        new() { Success = true, TransactionId = transactionId };

    public static PostingResult Failed(string errorCode, string errorMessage) =>
        new() { Success = false, ErrorCode = errorCode, ErrorMessage = errorMessage };
}
