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

namespace CashLineERP.Api.Tests;

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

        var integrationRegistryService = new IntegrationEndpointRegistryService(new IntegrationEndpointRegistryRepository(dbContext));
        var foreignExchangeQuoteService = new ForeignExchangeQuoteService(new ForeignExchangeQuoteRepository(dbContext));
        var foreignExchangeOverrideService = new ForeignExchangeOverrideService(new ForeignExchangeOverrideRepository(dbContext));
        var invoiceService = new AccountsReceivableInvoiceService(new AccountsReceivableInvoiceRepository(dbContext));
        var reportingService = new CoreReportingService(new CoreReportingRepository(dbContext));

        var endpoint = integrationRegistryService.CreateIntegrationEndpoint(new CreateIntegrationEndpointRequest(
            EndpointName: "Treasury FX feed",
            IntegrationProviderCode: "FX_SOURCE",
            EnvironmentCode: "UAT",
            DirectionCode: "INBOUND",
            TransportCode: "REST",
            HttpMethodCode: "POST",
            BaseUrl: "https://fx.uat.example.com",
            RelativePath: "/quotes",
            AuthenticationModeCode: "API_KEY",
            CredentialReference: "secret://fx/uat/key",
            TimeoutSeconds: 20,
            RetryPolicyCode: "STANDARD",
            MaxRetryCount: 2,
            IsIdempotencyKeyRequired: true,
            Notes: "Treasury FX source"));

        integrationRegistryService.SubmitIntegrationEndpoint(endpoint.IntegrationEndpointId, 2);
        integrationRegistryService.ApproveIntegrationEndpoint(endpoint.IntegrationEndpointId, 4);
        var activeEndpoint = integrationRegistryService.ActivateIntegrationEndpoint(endpoint.IntegrationEndpointId, 4);

        foreignExchangeQuoteService.IngestQuotes(3, new IngestForeignExchangeQuotesRequest(
            IntegrationEndpointId: activeEndpoint.IntegrationEndpointId,
            QuoteDate: new DateOnly(2026, 4, 20),
            BaseCurrencyCode: "EGP",
            SourceBatchReference: "FX-BATCH-001",
            Notes: "Opening quote batch",
            Quotes:
            [
                new IngestForeignExchangeQuoteLineRequest("USD", 48m, "USD-20260420", null)
            ]));

        foreignExchangeQuoteService.IngestQuotes(3, new IngestForeignExchangeQuotesRequest(
            IntegrationEndpointId: activeEndpoint.IntegrationEndpointId,
            QuoteDate: new DateOnly(2026, 4, 25),
            BaseCurrencyCode: "EGP",
            SourceBatchReference: "FX-BATCH-002",
            Notes: "Updated quote batch",
            Quotes:
            [
                new IngestForeignExchangeQuoteLineRequest("USD", 50m, "USD-20260425", null)
            ]));

        var createdOverride = foreignExchangeOverrideService.CreateForeignExchangeOverride(new CreateForeignExchangeOverrideRequest(
            EffectiveDate: new DateOnly(2026, 4, 22),
            BaseCurrencyCode: "EGP",
            CurrencyCode: "USD",
            OverrideRateToBase: 47m,
            ReasonCode: "TREASURY_MANUAL",
            Notes: "Temporary manual override"));

        var submittedOverride = foreignExchangeOverrideService.SubmitForeignExchangeOverride(createdOverride.ForeignExchangeOverrideId, 3);
        Assert.Equal("SUBMITTED", submittedOverride.StatusCode);

        var approvedOverride = foreignExchangeOverrideService.ApproveForeignExchangeOverride(createdOverride.ForeignExchangeOverrideId, 4);
        Assert.Equal("APPROVED", approvedOverride.StatusCode);
        Assert.Equal(47m, approvedOverride.OverrideRateToBase);

        var postedInvoiceBeforeNewQuote = AccountsReceivableWorkflowTestHelper.SubmitApproveAndPostInvoice(
            invoiceService,
            invoiceService.CreateInvoice(new CreateAccountsReceivableInvoiceRequest(
                CustomerId: 2,
                SalesOrderId: 1,
                DispatchOrderId: 1,
                InvoiceType: "TAX",
                InvoiceDate: new DateOnly(2026, 4, 23),
                TaxDate: new DateOnly(2026, 4, 23),
                DueDate: new DateOnly(2026, 4, 30),
                CurrencyCode: "USD",
                Lines:
                [
                    new CreateAccountsReceivableInvoiceLineRequest(1, 1001, 1m, "EA", 10m, "VAT14")
                ])).AccountsReceivableInvoiceId);

        var postedInvoiceAfterNewQuote = AccountsReceivableWorkflowTestHelper.SubmitApproveAndPostInvoice(
            invoiceService,
            invoiceService.CreateInvoice(new CreateAccountsReceivableInvoiceRequest(
                CustomerId: 2,
                SalesOrderId: 1,
                DispatchOrderId: 1,
                InvoiceType: "TAX",
                InvoiceDate: new DateOnly(2026, 4, 26),
                TaxDate: new DateOnly(2026, 4, 26),
                DueDate: new DateOnly(2026, 4, 30),
                CurrencyCode: "USD",
                Lines:
                [
                    new CreateAccountsReceivableInvoiceLineRequest(1, 1001, 1m, "EA", 10m, "VAT14")
                ])).AccountsReceivableInvoiceId);

        var earlyReport = reportingService.GetCoreFinanceReport(new DateOnly(2026, 4, 23), new DateOnly(2026, 4, 23));
        var earlyRow = earlyReport.Rows.Single(row => row.DocumentNumber == postedInvoiceBeforeNewQuote.InvoiceNumber && row.ReportSection == "AR");
        Assert.Equal(47m, earlyRow.FxRateToBase);

        var laterReport = reportingService.GetCoreFinanceReport(new DateOnly(2026, 4, 26), new DateOnly(2026, 4, 26));
        var laterRow = laterReport.Rows.Single(row => row.DocumentNumber == postedInvoiceAfterNewQuote.InvoiceNumber && row.ReportSection == "AR");
        Assert.Equal(50m, laterRow.FxRateToBase);
    }

    [Fact]
    public void FX_Override_Maker_Checker_Blocks_Self_Approval()
    {
        using var dbContext = QaDbContextFactory.CreateContext();

        var foreignExchangeOverrideService = new ForeignExchangeOverrideService(new ForeignExchangeOverrideRepository(dbContext));

        var createdOverride = foreignExchangeOverrideService.CreateForeignExchangeOverride(new CreateForeignExchangeOverrideRequest(
            EffectiveDate: new DateOnly(2026, 4, 24),
            BaseCurrencyCode: "EGP",
            CurrencyCode: "USD",
            OverrideRateToBase: 47.5m,
            ReasonCode: "FINANCE_CLOSE",
            Notes: "Month-end override"));

        foreignExchangeOverrideService.SubmitForeignExchangeOverride(createdOverride.ForeignExchangeOverrideId, 3);

        var exception = Assert.Throws<InvalidOperationException>(() =>
            foreignExchangeOverrideService.ApproveForeignExchangeOverride(createdOverride.ForeignExchangeOverrideId, 3));

        Assert.Contains("maker-checker", exception.Message, StringComparison.OrdinalIgnoreCase);
    }
}
