using CashLineERP.Application.Integration;
using CashLineERP.Application.Internal;
using CashLineERP.Contracts.Integration;
using CashLineERP.Infrastructure.Persistence.Repositories;

namespace CashLineERP.Api.Tests;

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

        var registryService = new IntegrationEndpointRegistryService(new IntegrationEndpointRegistryRepository(dbContext));
        var internalWorkbenchService = new InternalWorkbenchService(new InternalWorkbenchRepository(dbContext));

        var createdEndpoint = registryService.CreateIntegrationEndpoint(new CreateIntegrationEndpointRequest(
            EndpointName: "ETA invoice submission sandbox",
            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/signing",
            TimeoutSeconds: 45,
            RetryPolicyCode: "STANDARD",
            MaxRetryCount: 3,
            IsIdempotencyKeyRequired: true,
            Notes: "Operationalized sandbox endpoint"));

        Assert.Equal("DRAFT", createdEndpoint.StatusCode);
        Assert.False(createdEndpoint.IsActive);

        var submittedEndpoint = registryService.SubmitIntegrationEndpoint(createdEndpoint.IntegrationEndpointId, 2);
        Assert.Equal("SUBMITTED", submittedEndpoint.StatusCode);

        var approvalQueue = internalWorkbenchService.GetApprovalQueue("INTEGRATION");
        var approvalItem = Assert.Single(approvalQueue);
        Assert.Equal("INTEGRATION", approvalItem.ModuleCode);
        Assert.Equal("INTEGRATION_ENDPOINT", approvalItem.DocumentType);
        Assert.Equal(createdEndpoint.EndpointCode, approvalItem.DocumentNumber);

        var approvedEndpoint = registryService.ApproveIntegrationEndpoint(createdEndpoint.IntegrationEndpointId, 4);
        Assert.Equal("APPROVED", approvedEndpoint.StatusCode);

        var activeEndpoint = registryService.ActivateIntegrationEndpoint(createdEndpoint.IntegrationEndpointId, 4);
        Assert.True(activeEndpoint.IsActive);

        var activeEndpoints = registryService.GetIntegrationEndpoints(
            activeOnly: true,
            integrationProviderCode: "ETA",
            environmentCode: "TEST");
        var listedEndpoint = Assert.Single(activeEndpoints);
        Assert.Equal(createdEndpoint.IntegrationEndpointId, listedEndpoint.IntegrationEndpointId);
        Assert.Equal("SIGNATURE", listedEndpoint.AuthenticationModeCode);
    }

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

        var registryService = new IntegrationEndpointRegistryService(new IntegrationEndpointRegistryRepository(dbContext));

        var createdEndpoint = registryService.CreateIntegrationEndpoint(new CreateIntegrationEndpointRequest(
            EndpointName: "Notification callback",
            IntegrationProviderCode: "NOTIFICATION",
            EnvironmentCode: "UAT",
            DirectionCode: "INBOUND",
            TransportCode: "WEBHOOK",
            HttpMethodCode: "POST",
            BaseUrl: "https://notify.uat.example.com",
            RelativePath: "/callbacks/status",
            AuthenticationModeCode: "BEARER",
            CredentialReference: "secret://notify/uat/bearer",
            TimeoutSeconds: 30,
            RetryPolicyCode: "STANDARD",
            MaxRetryCount: 2,
            IsIdempotencyKeyRequired: true,
            Notes: "Webhook endpoint"));

        registryService.SubmitIntegrationEndpoint(createdEndpoint.IntegrationEndpointId, 2);

        var selfApprovalException = Assert.Throws<InvalidOperationException>(() =>
            registryService.ApproveIntegrationEndpoint(createdEndpoint.IntegrationEndpointId, 2));
        Assert.Contains("self-approval", selfApprovalException.Message, StringComparison.OrdinalIgnoreCase);

        registryService.ApproveIntegrationEndpoint(createdEndpoint.IntegrationEndpointId, 4);
        registryService.ActivateIntegrationEndpoint(createdEndpoint.IntegrationEndpointId, 4);

        var duplicateEndpoint = registryService.CreateIntegrationEndpoint(new CreateIntegrationEndpointRequest(
            EndpointName: "Notification callback duplicate",
            IntegrationProviderCode: "NOTIFICATION",
            EnvironmentCode: "UAT",
            DirectionCode: "INBOUND",
            TransportCode: "WEBHOOK",
            HttpMethodCode: "POST",
            BaseUrl: "https://notify.uat.example.com",
            RelativePath: "/callbacks/status",
            AuthenticationModeCode: "BEARER",
            CredentialReference: "secret://notify/uat/bearer-2",
            TimeoutSeconds: 30,
            RetryPolicyCode: "STANDARD",
            MaxRetryCount: 2,
            IsIdempotencyKeyRequired: true,
            Notes: "Duplicate active route"));

        registryService.SubmitIntegrationEndpoint(duplicateEndpoint.IntegrationEndpointId, 2);
        registryService.ApproveIntegrationEndpoint(duplicateEndpoint.IntegrationEndpointId, 4);

        var duplicateActivationException = Assert.Throws<InvalidOperationException>(() =>
            registryService.ActivateIntegrationEndpoint(duplicateEndpoint.IntegrationEndpointId, 4));
        Assert.Contains("already exists", duplicateActivationException.Message, StringComparison.OrdinalIgnoreCase);
    }
}
