using Books.Api.Domain.Invoices;
using EventFlow.Commands;

namespace Books.Api.Commands.Invoices;

/// <summary>
/// Creates a new invoice draft for a customer.
/// Invoice number is assigned at creation (Momsloven §52).
/// </summary>
public class CreateInvoiceCommand(
    InvoiceId invoiceId,
    string companyId,
    string fiscalYearId,
    string customerId,
    string customerName,
    string customerNumber,
    string invoiceNumber,
    DateOnly invoiceDate,
    DateOnly dueDate,
    int paymentTermsDays,
    string currency,
    string? vatCode,
    string? notes,
    string? reference,
    string createdBy) : Command<InvoiceAggregate, InvoiceId>(invoiceId)
{
    public string CompanyId { get; } = companyId;
    public string FiscalYearId { get; } = fiscalYearId;
    public string CustomerId { get; } = customerId;
    public string CustomerName { get; } = customerName;
    public string CustomerNumber { get; } = customerNumber;
    public string InvoiceNumber { get; } = invoiceNumber;
    public DateOnly InvoiceDate { get; } = invoiceDate;
    public DateOnly DueDate { get; } = dueDate;
    public int PaymentTermsDays { get; } = paymentTermsDays;
    public string Currency { get; } = currency;
    public string? VatCode { get; } = vatCode;
    public string? Notes { get; } = notes;
    public string? Reference { get; } = reference;
    public string CreatedBy { get; } = createdBy;
}

/// <summary>
/// Adds a line to an invoice draft.
/// </summary>
public class AddInvoiceLineCommand(
    InvoiceId invoiceId,
    string description,
    decimal quantity,
    decimal unitPrice,
    string vatCode,
    string? accountId = null,
    string? unit = null,
    decimal discountPercent = 0) : Command<InvoiceAggregate, InvoiceId>(invoiceId)
{
    public string Description { get; } = description;
    public decimal Quantity { get; } = quantity;
    public decimal UnitPrice { get; } = unitPrice;
    public string VatCode { get; } = vatCode;
    public string? AccountId { get; } = accountId;
    public string? Unit { get; } = unit;
    public decimal DiscountPercent { get; } = discountPercent;
}

/// <summary>
/// Updates a line on an invoice draft.
/// </summary>
public class UpdateInvoiceLineCommand(
    InvoiceId invoiceId,
    int lineNumber,
    string description,
    decimal quantity,
    decimal unitPrice,
    string vatCode,
    string? accountId = null,
    string? unit = null,
    decimal discountPercent = 0) : Command<InvoiceAggregate, InvoiceId>(invoiceId)
{
    public int LineNumber { get; } = lineNumber;
    public string Description { get; } = description;
    public decimal Quantity { get; } = quantity;
    public decimal UnitPrice { get; } = unitPrice;
    public string VatCode { get; } = vatCode;
    public string? AccountId { get; } = accountId;
    public string? Unit { get; } = unit;
    public decimal DiscountPercent { get; } = discountPercent;
}

/// <summary>
/// Removes a line from an invoice draft.
/// </summary>
public class RemoveInvoiceLineCommand(
    InvoiceId invoiceId,
    int lineNumber) : Command<InvoiceAggregate, InvoiceId>(invoiceId)
{
    public int LineNumber { get; } = lineNumber;
}

/// <summary>
/// Marks an invoice as sent and records the ledger transaction.
/// Should be called after successfully posting to the ledger.
/// </summary>
public class MarkInvoiceSentCommand(
    InvoiceId invoiceId,
    string ledgerTransactionId,
    string sentBy) : Command<InvoiceAggregate, InvoiceId>(invoiceId)
{
    public string LedgerTransactionId { get; } = ledgerTransactionId;
    public string SentBy { get; } = sentBy;
}

/// <summary>
/// Records a payment received for an invoice.
/// </summary>
public class ReceiveInvoicePaymentCommand(
    InvoiceId invoiceId,
    decimal amount,
    string? bankTransactionId,
    string? ledgerTransactionId,
    string? paymentReference,
    DateOnly paymentDate,
    string recordedBy) : Command<InvoiceAggregate, InvoiceId>(invoiceId)
{
    public decimal Amount { get; } = amount;
    public string? BankTransactionId { get; } = bankTransactionId;
    public string? LedgerTransactionId { get; } = ledgerTransactionId;
    public string? PaymentReference { get; } = paymentReference;
    public DateOnly PaymentDate { get; } = paymentDate;
    public string RecordedBy { get; } = recordedBy;
}

/// <summary>
/// Voids an invoice. If already sent, includes the reversal transaction ID.
/// </summary>
public class VoidInvoiceCommand(
    InvoiceId invoiceId,
    string reason,
    string? reversalLedgerTransactionId,
    string voidedBy) : Command<InvoiceAggregate, InvoiceId>(invoiceId)
{
    public string Reason { get; } = reason;
    public string? ReversalLedgerTransactionId { get; } = reversalLedgerTransactionId;
    public string VoidedBy { get; } = voidedBy;
}
