using CashLineERP.Application.Finance;
using CashLineERP.Contracts.Finance;
using CashLineERP.Infrastructure.Persistence.Repositories;

namespace CashLineERP.Api.Tests;

public sealed class CustomerStatementServiceQaTests
{
    [Fact]
    public void Customer_Statements_Can_Be_Generated_And_Delivery_Logged()
    {
        using var dbContext = QaDbContextFactory.CreateContext();

        var invoiceService = new AccountsReceivableInvoiceService(new AccountsReceivableInvoiceRepository(dbContext));
        var receiptService = new AccountsReceivableReceiptService(new AccountsReceivableReceiptRepository(dbContext));
        var statementService = new CustomerStatementService(new CustomerStatementRepository(dbContext));

        var postedInvoice = AccountsReceivableWorkflowTestHelper.SubmitApproveAndPostInvoice(
            invoiceService,
            invoiceService.CreateInvoice(new CreateAccountsReceivableInvoiceRequest(
                CustomerId: 2,
                SalesOrderId: 1,
                DispatchOrderId: 1,
                InvoiceType: "TAX",
                InvoiceDate: new DateOnly(2026, 5, 10),
                TaxDate: new DateOnly(2026, 5, 10),
                DueDate: new DateOnly(2026, 5, 20),
                CurrencyCode: "EGP",
                Lines:
                [
                    new CreateAccountsReceivableInvoiceLineRequest(1, 1001, 2m, "EA", 50m, "VAT14")
                ])).AccountsReceivableInvoiceId);

        var postedReceipt = AccountsReceivableWorkflowTestHelper.SubmitApproveAndPostReceipt(
            receiptService,
            receiptService.CreateReceipt(new CreateAccountsReceivableReceiptRequest(
                CustomerId: 2,
                ReceiptDate: new DateOnly(2026, 5, 15),
                ReceiptMethod: "BANK_TRANSFER",
                CurrencyCode: "EGP",
                AmountAmount: 60m,
                ReferenceNumber: "CUST-STMT-RCPT-001",
                Notes: "Customer statement receipt",
                Allocations:
                [
                    new CreateAccountsReceivableReceiptAllocationRequest(postedInvoice.AccountsReceivableInvoiceId, 60m, new DateOnly(2026, 5, 15))
                ])).AccountsReceivableReceiptId);

        var statement = statementService.GenerateStatement(3, new CreateCustomerStatementRequest(
            CustomerId: 2,
            DateFrom: new DateOnly(2026, 5, 1),
            DateTo: new DateOnly(2026, 5, 31),
            CurrencyCode: "EGP"));

        Assert.StartsWith("CSTMT-", statement.StatementNumber);
        Assert.Equal(2L, statement.CustomerId);
        Assert.Equal("EGP", statement.CurrencyCode);
        Assert.Equal(0m, statement.OpeningBalanceAmount);
        Assert.Equal(114m, statement.TotalChargeAmount);
        Assert.Equal(60m, statement.TotalSettlementAmount);
        Assert.Equal(54m, statement.ClosingBalanceAmount);
        Assert.Equal(54m, statement.OpenInvoiceAmount);
        Assert.Equal(54m, statement.OverdueInvoiceAmount);
        Assert.Equal(2, statement.Lines.Count);
        Assert.Contains(statement.Lines, line => line.DocumentNumber == postedInvoice.InvoiceNumber && line.ChargeAmount == 114m);
        Assert.Contains(statement.Lines, line => line.DocumentNumber == postedReceipt.ReceiptNumber && line.SettlementAmount == 60m);

        var delivery = statementService.RecordDelivery(statement.CustomerStatementId, 4, new RecordCustomerStatementDeliveryRequest(
            DeliveredAtUtc: new DateTime(2026, 5, 31, 14, 0, 0, DateTimeKind.Utc),
            ChannelCode: "email",
            RecipientAddress: "receivables@customer.test",
            DeliveryStatusCode: "sent",
            Notes: "Monthly statement delivered."));

        Assert.Equal(statement.CustomerStatementId, delivery.CustomerStatementId);
        Assert.Equal("EMAIL", delivery.ChannelCode);
        Assert.Equal("SENT", delivery.DeliveryStatusCode);

        var deliveryLogs = statementService.GetDeliveryLogs(statement.CustomerStatementId);
        Assert.Single(deliveryLogs);
        Assert.Equal("receivables@customer.test", deliveryLogs.Single().RecipientAddress);

        var statements = statementService.GetStatements(2);
        Assert.Contains(statements, item => item.CustomerStatementId == statement.CustomerStatementId && item.DeliveryLogCount == 1);

        var detail = statementService.GetStatement(statement.CustomerStatementId);
        Assert.NotNull(detail);
        Assert.Single(detail!.DeliveryLogs);
    }
}
