using CashLineERP.Application.Finance;
using CashLineERP.Application.Integration;
using CashLineERP.Application.Reporting;
using CashLineERP.Application.Tax;
using CashLineERP.Contracts.Finance;
using CashLineERP.Contracts.Integration;
using CashLineERP.Contracts.Reporting;
using CashLineERP.Contracts.Tax;
using CashLineERP.Infrastructure.Persistence.Repositories;

namespace CashLineERP.Api.Tests;

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

        var reportingService = new CoreReportingService(new CoreReportingRepository(dbContext));
        var integrationRegistryService = new IntegrationEndpointRegistryService(new IntegrationEndpointRegistryRepository(dbContext));
        var invoiceService = new AccountsReceivableInvoiceService(new AccountsReceivableInvoiceRepository(dbContext));
        var etaService = new EtaComplianceService(new EtaComplianceRepository(dbContext));
        var outboxService = new OutboxEventService(new OutboxEventRepository(dbContext));

        var snapshot = reportingService.GenerateReportingSnapshot(2, new CreateReportingSnapshotRequest(
            ReportCode: "CORE_FINANCE",
            DateFrom: new DateOnly(2026, 4, 1),
            DateTo: new DateOnly(2026, 4, 30),
            AsOfDate: null,
            Notes: "Outbox baseline reporting snapshot"));

        var endpoint = integrationRegistryService.CreateIntegrationEndpoint(new CreateIntegrationEndpointRequest(
            EndpointName: "ETA outbound sandbox endpoint",
            IntegrationProviderCode: "ETA",
            EnvironmentCode: "TEST",
            DirectionCode: "OUTBOUND",
            TransportCode: "REST",
            HttpMethodCode: "POST",
            BaseUrl: "https://eta.test.eg",
            RelativePath: "/api/v1/invoices",
            AuthenticationModeCode: "SIGNATURE",
            CredentialReference: "secret://eta/test/signature",
            TimeoutSeconds: 30,
            RetryPolicyCode: "STANDARD",
            MaxRetryCount: 3,
            IsIdempotencyKeyRequired: true,
            Notes: "Outbox baseline endpoint"));
        integrationRegistryService.SubmitIntegrationEndpoint(endpoint.IntegrationEndpointId, 2);
        integrationRegistryService.ApproveIntegrationEndpoint(endpoint.IntegrationEndpointId, 4);
        integrationRegistryService.ActivateIntegrationEndpoint(endpoint.IntegrationEndpointId, 4);

        var invoice = invoiceService.CreateInvoice(new CreateAccountsReceivableInvoiceRequest(
            CustomerId: 2,
            SalesOrderId: 1,
            DispatchOrderId: 1,
            InvoiceType: "TAX",
            InvoiceDate: new DateOnly(2026, 4, 18),
            TaxDate: new DateOnly(2026, 4, 18),
            DueDate: new DateOnly(2026, 4, 28),
            CurrencyCode: "EGP",
            Lines:
            [
                new CreateAccountsReceivableInvoiceLineRequest(1, 1001, 2m, "EA", 32m, "VAT14")
            ]));
        var postedInvoice = AccountsReceivableWorkflowTestHelper.SubmitApproveAndPostInvoice(invoiceService, invoice.AccountsReceivableInvoiceId);
        var submission = etaService.SubmitInvoice(postedInvoice.AccountsReceivableInvoiceId, new SubmitInvoiceToEtaRequest(
            ActorUserId: 4,
            PayloadText: null));

        var pendingEvents = outboxService.GetOutboxEvents("PENDING", null);
        Assert.True(pendingEvents.Count >= 3);
        Assert.Contains(pendingEvents, item => item.EventType == "REPORTING_SNAPSHOT_GENERATED" && item.AggregateId == snapshot.ReportingSnapshotId);
        Assert.Contains(pendingEvents, item => item.EventType == "INTEGRATION_ENDPOINT_ACTIVATED" && item.AggregateId == endpoint.IntegrationEndpointId);
        Assert.Contains(pendingEvents, item => item.EventType == "ETA_SUBMISSION_QUEUED" && item.CorrelationKey == submission.SubmissionReference);

        var publishResult = outboxService.PublishPendingEvents(new PublishOutboxBatchRequest(
            PublisherCode: "WORKER_BASELINE",
            BatchSize: 10));

        Assert.True(publishResult.PublishedCount >= 3);
        Assert.All(publishResult.PublishedEvents, item =>
        {
            Assert.Equal("PUBLISHED", item.StatusCode);
            Assert.Equal("WORKER_BASELINE", item.PublishedByProcess);
            Assert.NotNull(item.PublishedAtUtc);
        });
    }
}
