using CashLineERP.Application.Integration;
using CashLineERP.Contracts.Integration;
using CashLineERP.Infrastructure.Persistence.Repositories;
using CashLineERP.SharedKernel.IslamicFinance;

namespace CashLineERP.Api.Tests;

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

        var seed = IslamicFinanceIntegrationTestSeeder.SeedOperationalLifecycle(dbContext);
        var outboxService = new OutboxEventService(new OutboxEventRepository(dbContext));

        var pendingEvents = outboxService.GetOutboxEvents("PENDING", IslamicFinanceIntegrationEventCatalog.SourceModuleCode);

        Assert.Contains(pendingEvents, item => item.EventType == IslamicFinanceIntegrationEventCatalog.FinancingRequestCreated && item.CorrelationKey == seed.RequestNumber);
        Assert.Contains(pendingEvents, item => item.EventType == IslamicFinanceIntegrationEventCatalog.FinancingRequestSubmitted && item.CorrelationKey == seed.RequestNumber);
        Assert.Contains(pendingEvents, item => item.EventType == IslamicFinanceIntegrationEventCatalog.FinancingRequestApproved && item.CorrelationKey == seed.RequestNumber);
        Assert.Contains(pendingEvents, item => item.EventType == IslamicFinanceIntegrationEventCatalog.FinancingRequestPartnerAssigned && item.CorrelationKey == seed.RequestNumber);
        Assert.Contains(pendingEvents, item => item.EventType == IslamicFinanceIntegrationEventCatalog.FinancingRequestShariahAttached && item.CorrelationKey == seed.RequestNumber);

        Assert.Contains(pendingEvents, item => item.EventType == IslamicFinanceIntegrationEventCatalog.FinancingDecisionCreated && item.CorrelationKey == seed.RequestNumber);
        Assert.Contains(pendingEvents, item => item.EventType == IslamicFinanceIntegrationEventCatalog.FinancingDecisionSubmitted && item.CorrelationKey == seed.RequestNumber);
        Assert.Contains(pendingEvents, item => item.EventType == IslamicFinanceIntegrationEventCatalog.FinancingDecisionApproved && item.CorrelationKey == seed.RequestNumber);

        Assert.Contains(pendingEvents, item => item.EventType == IslamicFinanceIntegrationEventCatalog.ShariahReviewCreated && item.CorrelationKey == seed.ReviewCaseNumber);
        Assert.Contains(pendingEvents, item => item.EventType == IslamicFinanceIntegrationEventCatalog.ShariahReviewSubmitted && item.CorrelationKey == seed.ReviewCaseNumber);
        Assert.Contains(pendingEvents, item => item.EventType == IslamicFinanceIntegrationEventCatalog.ShariahReviewRecommended && item.CorrelationKey == seed.ReviewCaseNumber);
        Assert.Contains(pendingEvents, item => item.EventType == IslamicFinanceIntegrationEventCatalog.ShariahReviewDecided && item.CorrelationKey == seed.ReviewCaseNumber);

        Assert.Contains(pendingEvents, item => item.EventType == IslamicFinanceIntegrationEventCatalog.MurabahaCaseCreated && item.CorrelationKey == seed.MurabahaCaseNumber);
        Assert.Contains(pendingEvents, item => item.EventType == IslamicFinanceIntegrationEventCatalog.MurabahaCaseSubmitted && item.CorrelationKey == seed.MurabahaCaseNumber);
        Assert.Contains(pendingEvents, item => item.EventType == IslamicFinanceIntegrationEventCatalog.MurabahaCaseApproved && item.CorrelationKey == seed.MurabahaCaseNumber);
        Assert.Contains(pendingEvents, item => item.EventType == IslamicFinanceIntegrationEventCatalog.MurabahaCaseActivated && item.CorrelationKey == seed.MurabahaCaseNumber);
        Assert.Contains(pendingEvents, item => item.EventType == IslamicFinanceIntegrationEventCatalog.MurabahaScheduleGenerated && item.CorrelationKey == seed.MurabahaCaseNumber);

        Assert.Contains(pendingEvents, item => item.EventType == IslamicFinanceIntegrationEventCatalog.SettlementCreated && item.CorrelationKey == seed.DisbursementNumber);
        Assert.Contains(pendingEvents, item => item.EventType == IslamicFinanceIntegrationEventCatalog.SettlementSubmitted && item.CorrelationKey == seed.DisbursementNumber);
        Assert.Contains(pendingEvents, item => item.EventType == IslamicFinanceIntegrationEventCatalog.SettlementApproved && item.CorrelationKey == seed.DisbursementNumber);
        Assert.Contains(pendingEvents, item => item.EventType == IslamicFinanceIntegrationEventCatalog.SettlementExecuted && item.CorrelationKey == seed.DisbursementNumber);
        Assert.Contains(pendingEvents, item => item.EventType == IslamicFinanceIntegrationEventCatalog.SettlementClosed && item.CorrelationKey == seed.DisbursementNumber);

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

        Assert.True(publishResult.PublishedCount >= 20);
        Assert.Contains(publishResult.PublishedEvents, item => item.EventType == IslamicFinanceIntegrationEventCatalog.MurabahaScheduleGenerated);
        Assert.Contains(publishResult.PublishedEvents, item => item.EventType == IslamicFinanceIntegrationEventCatalog.SettlementClosed);
        Assert.All(publishResult.PublishedEvents, item =>
        {
            Assert.Equal("PUBLISHED", item.StatusCode);
            Assert.Equal("IF_EVENT_WORKER", item.PublishedByProcess);
        });
    }

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

        var registryService = new IntegrationEndpointRegistryService(new IntegrationEndpointRegistryRepository(dbContext));
        var inboxService = new InboxMessageService(new InboxMessageRepository(dbContext));

        var endpoint = registryService.CreateIntegrationEndpoint(new CreateIntegrationEndpointRequest(
            EndpointName: "Islamic Finance inbound status gateway",
            IntegrationProviderCode: "NOTIFICATION",
            EnvironmentCode: "TEST",
            DirectionCode: "INBOUND",
            TransportCode: "WEBHOOK",
            HttpMethodCode: "POST",
            BaseUrl: "https://if.test.example",
            RelativePath: "/callbacks/islamic-finance",
            AuthenticationModeCode: "SIGNATURE",
            CredentialReference: "secret://if/test/signature",
            TimeoutSeconds: 20,
            RetryPolicyCode: "STANDARD",
            MaxRetryCount: 3,
            IsIdempotencyKeyRequired: true,
            Notes: "Islamic Finance inbox baseline endpoint"));
        registryService.SubmitIntegrationEndpoint(endpoint.IntegrationEndpointId, 2);
        registryService.ApproveIntegrationEndpoint(endpoint.IntegrationEndpointId, 4);
        endpoint = registryService.ActivateIntegrationEndpoint(endpoint.IntegrationEndpointId, 4);

        var requestStatus = inboxService.ReceiveInboxMessage(2, new ReceiveInboxMessageRequest(
            endpoint.IntegrationEndpointId,
            IslamicFinanceIntegrationEventCatalog.NormalizeInboxMessageType("if_request_status"),
            "IF-IN-REQ-001",
            "REQ-IF-001",
            "{\"status\":\"approved\"}"));

        var shariahStatus = inboxService.ReceiveInboxMessage(2, new ReceiveInboxMessageRequest(
            endpoint.IntegrationEndpointId,
            IslamicFinanceIntegrationEventCatalog.NormalizeInboxMessageType("IF_SHARIAH_STATUS"),
            "IF-IN-SHR-001",
            "SHR-IF-001",
            "{\"status\":\"approved\"}"));

        var murabahaStatus = inboxService.ReceiveInboxMessage(2, new ReceiveInboxMessageRequest(
            endpoint.IntegrationEndpointId,
            IslamicFinanceIntegrationEventCatalog.NormalizeInboxMessageType("IF_MURABAHA_STATUS"),
            "IF-IN-MUR-001",
            "MUR-IF-001",
            "{\"status\":\"active\"}"));

        var settlementStatus = inboxService.ReceiveInboxMessage(2, new ReceiveInboxMessageRequest(
            endpoint.IntegrationEndpointId,
            IslamicFinanceIntegrationEventCatalog.NormalizeInboxMessageType("IF_SETTLEMENT_STATUS"),
            "IF-IN-SET-001",
            "SET-IF-001",
            "{\"status\":\"executed\"}"));

        Assert.Equal("RECEIVED", requestStatus.StatusCode);
        Assert.Equal("RECEIVED", settlementStatus.StatusCode);

        var receivedMessages = inboxService.GetInboxMessages("RECEIVED", "NOTIFICATION");
        Assert.Equal(4, receivedMessages.Count);
        Assert.Contains(receivedMessages, item => item.MessageType == IslamicFinanceIntegrationEventCatalog.RequestStatusMessageType);
        Assert.Contains(receivedMessages, item => item.MessageType == IslamicFinanceIntegrationEventCatalog.ShariahStatusMessageType);
        Assert.Contains(receivedMessages, item => item.MessageType == IslamicFinanceIntegrationEventCatalog.MurabahaStatusMessageType);
        Assert.Contains(receivedMessages, item => item.MessageType == IslamicFinanceIntegrationEventCatalog.SettlementStatusMessageType);

        var processResult = inboxService.ProcessPendingMessages(new ProcessInboxBatchRequest(
            ProcessorCode: "IF_INBOX_WORKER",
            BatchSize: 10));

        Assert.Equal(4, processResult.ProcessedCount);
        Assert.All(processResult.ProcessedMessages, item =>
        {
            Assert.Equal("PROCESSED", item.StatusCode);
            Assert.Equal("IF_INBOX_WORKER", item.ProcessedByProcess);
        });
    }
}
