using CashLineERP.Application.External;
using CashLineERP.Application.Finance;
using CashLineERP.Application.Integration;
using CashLineERP.Application.Inventory;
using CashLineERP.Application.IslamicFinance.Disbursements;
using CashLineERP.Application.IslamicFinance.ProductProfiles;
using CashLineERP.Application.IslamicFinance.ReceivablesFinance;
using CashLineERP.Application.IslamicFinance.Requests;
using CashLineERP.Application.IslamicFinance.Settlements;
using CashLineERP.Application.Notifications;
using CashLineERP.Application.Tax;
using CashLineERP.Application.Internal;
using CashLineERP.Application.Parties;
using CashLineERP.Application.Reporting;
using CashLineERP.Application.Sales;
using CashLineERP.Application.Suppliers;
using CashLineERP.Application.Customers;
using CashLineERP.Contracts.Finance;
using CashLineERP.Contracts.Inventory;
using CashLineERP.Infrastructure.Persistence;
using CashLineERP.Infrastructure.Persistence.Repositories;
using CashLineERP.Infrastructure.Persistence.Repositories.IslamicFinance;
using CashLineERP.SharedKernel.IslamicFinance;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;

namespace CashLineERP.Api.Tests;

public sealed class ProviderCompatibilityQaTests
{
    [Fact]
    public void Sqlite_Relational_Provider_Supports_Current_Read_Model_Baseline()
    {
        using var connection = QaDbContextFactory.CreateOpenSqliteConnection();
        using var dbContext = QaDbContextFactory.CreateSqliteContext(connection);

        var reportingService = new CoreReportingService(new CoreReportingRepository(dbContext));
        var internalWorkbenchService = new InternalWorkbenchService(new InternalWorkbenchRepository(dbContext));
        var supplierProfileService = new SupplierProfileService(new SupplierProfileRepository(dbContext));
        var customerProfileService = new CustomerProfileService(new CustomerProfileRepository(dbContext));
        var partyOnboardingService = new PartyOnboardingService(new BusinessPartyRepository(dbContext));
        var salesOrderService = new SalesOrderService(new SalesOrderRepository(dbContext));
        var islamicFinanceProductService = new IslamicFinanceProductService(new IslamicFinanceProductRepository(dbContext));
        var islamicFinanceRequestService = new IslamicFinanceRequestService(new IslamicFinanceRequestRepository(dbContext));
        var receivablesFinanceService = new ReceivablesFinanceService(new ReceivablesFinanceRepository(dbContext));
        var disbursementService = new IslamicFinanceMurabahaDisbursementService(new IslamicFinanceMurabahaDisbursementRepository(dbContext));
        var settlementService = new IslamicFinanceSettlementService(new IslamicFinanceSettlementRepository(dbContext));
        var notificationTemplateService = new NotificationTemplateService(new NotificationTemplateRepository(dbContext));
        var notificationOrchestrationService = new NotificationOrchestrationService(new NotificationOrchestrationRepository(dbContext));
        var paymentGatewayExecutionService = new PaymentGatewayExecutionService(new PaymentGatewayExecutionRepository(dbContext));
        var externalPortalService = new ExternalPortalService(
            new ExternalPortalRepository(dbContext),
            supplierProfileService,
            customerProfileService,
            partyOnboardingService,
            salesOrderService,
            islamicFinanceProductService,
            islamicFinanceRequestService,
            receivablesFinanceService,
            disbursementService,
            settlementService,
            notificationTemplateService,
            notificationOrchestrationService,
            paymentGatewayExecutionService);
        var invoiceService = new AccountsReceivableInvoiceService(new AccountsReceivableInvoiceRepository(dbContext));

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

        var financeReport = reportingService.GetCoreFinanceReport(new DateOnly(2026, 4, 1), new DateOnly(2026, 4, 30));
        Assert.True(financeReport.PostedAccountsPayableBillCount >= 1);
        Assert.True(financeReport.PostedAccountsReceivableInvoiceCount >= 1);

        var operationsReport = reportingService.GetCoreOperationsReport(new DateOnly(2026, 4, 1), new DateOnly(2026, 4, 30));
        Assert.True(operationsReport.PurchaseOrderCount >= 1);
        Assert.True(operationsReport.SalesOrderCount >= 1);

        var dashboard = internalWorkbenchService.GetDashboardSummary();
        Assert.True(dashboard.PendingApprovalCount >= 0);
        Assert.True(dashboard.TotalExceptionCount >= 0);

        var supplierSummary = externalPortalService.GetStatementSummary(1);
        Assert.Equal("SUPPLIER", supplierSummary.PartyType);
        Assert.True(supplierSummary.InvoiceCount >= 1);

        var customerSummary = externalPortalService.GetStatementSummary(2);
        Assert.Equal("CUSTOMER", customerSummary.PartyType);
        Assert.True(customerSummary.InvoiceCount >= 1);
    }

    [Fact]
    public void Sqlite_Relational_Provider_Supports_Month_End_Readiness_And_Eta_Control_Baseline()
    {
        using var connection = QaDbContextFactory.CreateOpenSqliteConnection();
        using var dbContext = QaDbContextFactory.CreateSqliteContext(connection);

        var invoiceService = new AccountsReceivableInvoiceService(new AccountsReceivableInvoiceRepository(dbContext));
        var adjustmentService = new InventoryAdjustmentService(new InventoryAdjustmentRepository(dbContext));
        var accountingPeriodService = new AccountingPeriodService(new AccountingPeriodRepository(dbContext));
        var taxService = new StatutoryTaxService(new StatutoryTaxRepository(dbContext));
        var etaService = new EtaComplianceService(new EtaComplianceRepository(dbContext));

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

        adjustmentService.CreateInventoryAdjustment(new CreateInventoryAdjustmentRequest(
            BranchId: 1,
            WarehouseId: 1,
            AdjustmentDate: new DateOnly(2026, 4, 22),
            ReasonCode: "COUNT_VARIANCE",
            Notes: "SQLite month-end draft adjustment",
            Lines:
            [
                new CreateInventoryAdjustmentLineRequest(1001, null, -1m, "EA", 20m, "AVAILABLE", "SQLITE-ADJ-01", null, "SQLite pending adjustment")
            ]));

        var readiness = accountingPeriodService.GetCloseReadiness(1);
        Assert.True(readiness.OpenArInvoiceCount >= 1);
        Assert.True(readiness.OpenInventoryAdjustmentCount >= 1);
        Assert.False(readiness.IsReadyToClose);

        var review = accountingPeriodService.GetMonthEndReview(1);
        Assert.True(review.OpenItems.Count >= 2);
        Assert.Contains(review.OpenItems, item => item.DocumentType == "AR_INVOICE");
        Assert.Contains(review.OpenItems, item => item.DocumentType == "INV_ADJUSTMENT");

        var validationPack = etaService.GetSubmissionValidationPack(postedInvoice.AccountsReceivableInvoiceId);
        Assert.NotNull(validationPack);
        Assert.True(validationPack!.IsValid);

        var preview = etaService.GetPayloadPreview(postedInvoice.AccountsReceivableInvoiceId);
        Assert.NotNull(preview);
        Assert.True(preview!.IsStatutoryReady);

        var package = taxService.GetAccountsReceivableInvoiceFinanceReviewPackage(postedInvoice.AccountsReceivableInvoiceId);
        Assert.NotNull(package);
        Assert.Equal("AR_INVOICE", package!.DocumentType);
        Assert.True(package.Entries.Count >= 3);
    }

    [Fact]
    public void Sqlite_Relational_Provider_Supports_Islamic_Finance_Murabaha_First_Baseline()
    {
        using var connection = QaDbContextFactory.CreateOpenSqliteConnection();
        using var dbContext = QaDbContextFactory.CreateSqliteContext(connection);

        var seed = IslamicFinanceIntegrationTestSeeder.SeedOperationalLifecycle(dbContext);
        var reportingService = new CoreReportingService(new CoreReportingRepository(dbContext));
        var internalWorkbenchService = new InternalWorkbenchService(new InternalWorkbenchRepository(dbContext));
        var outboxService = new OutboxEventService(new OutboxEventRepository(dbContext));

        var pipeline = reportingService.GetIslamicFinancePipelineReport(
            new DateOnly(2026, 4, 1),
            new DateOnly(2026, 4, 30),
            seed.PartnerLenderId);
        Assert.NotNull(pipeline);
        Assert.True(pipeline.Rows.Count >= 4);
        Assert.Contains(pipeline.Rows, row => row.StageCode == "REQUEST" && row.RecordId == seed.FinancingRequestId);
        Assert.Contains(pipeline.Rows, row => row.StageCode == "MURABAHA" && row.RecordId == seed.MurabahaCaseId);

        var dashboard = internalWorkbenchService.GetDashboardSummary();
        Assert.True(dashboard.PendingApprovalCount >= 0);

        var outboxEvents = outboxService.GetOutboxEvents("PENDING", IslamicFinanceIntegrationEventCatalog.SourceModuleCode);
        Assert.Contains(outboxEvents, item => item.EventType == IslamicFinanceIntegrationEventCatalog.MurabahaCaseActivated && item.CorrelationKey == seed.MurabahaCaseNumber);
        Assert.Contains(outboxEvents, item => item.EventType == IslamicFinanceIntegrationEventCatalog.SettlementExecuted && item.CorrelationKey == seed.DisbursementNumber);
    }

    [Fact]
    public void SqlServer_Provider_Generates_Current_Islamic_Finance_Schema_Model()
    {
        var options = new DbContextOptionsBuilder<CashLineErpDbContext>()
            .UseSqlServer("Server=localhost;Database=CashLineERP_ProviderQualification;Trusted_Connection=True;TrustServerCertificate=True")
            .ConfigureWarnings(warnings => warnings.Ignore(CoreEventId.ManyServiceProvidersCreatedWarning))
            .Options;

        using var dbContext = new CashLineErpDbContext(options);
        var script = dbContext.Database.GenerateCreateScript();

        Assert.Contains("if_partner_lender", script, StringComparison.OrdinalIgnoreCase);
        Assert.Contains("if_product_profile", script, StringComparison.OrdinalIgnoreCase);
        Assert.Contains("if_facility", script, StringComparison.OrdinalIgnoreCase);
        Assert.Contains("if_financing_request", script, StringComparison.OrdinalIgnoreCase);
        Assert.Contains("if_financing_decision", script, StringComparison.OrdinalIgnoreCase);
        Assert.Contains("if_shariah_review_case", script, StringComparison.OrdinalIgnoreCase);
        Assert.Contains("if_murabaha_case", script, StringComparison.OrdinalIgnoreCase);
        Assert.Contains("if_murabaha_asset", script, StringComparison.OrdinalIgnoreCase);
        Assert.Contains("if_disbursement", script, StringComparison.OrdinalIgnoreCase);
        Assert.Contains("if_profit_schedule", script, StringComparison.OrdinalIgnoreCase);
        Assert.Contains("if_accounting_hook", script, StringComparison.OrdinalIgnoreCase);
        Assert.Contains("int_outbox_evt", script, StringComparison.OrdinalIgnoreCase);
        Assert.Contains("int_inbox_msg", script, StringComparison.OrdinalIgnoreCase);
    }
}
