using Eis.Infrastructure.Administration;

namespace Eis.Infrastructure.Tests.Administration;

public sealed class AdminMigrationOptionsTests
{
    [Fact]
    public void DisabledByDefault()
    {
        WithEnvironment(null, null, null, () =>
        {
            var options = AdminMigrationOptions.FromEnvironment(
                configuredNativeReadsEnabled: false,
                authenticationNativeEnabled: false,
                sharesLegacySessions: false);

            Assert.False(options.NativeReadsEnabled);
        });
    }

    [Fact]
    public void RequiresNativeAuthentication()
    {
        WithEnvironment("true", null, "true", () =>
        {
            var exception = Assert.Throws<InvalidOperationException>(() =>
                AdminMigrationOptions.FromEnvironment(
                    configuredNativeReadsEnabled: false,
                    authenticationNativeEnabled: false,
                    sharesLegacySessions: false));

            Assert.Contains("AUTH_NATIVE_ENABLED=true", exception.Message);
        });
    }

    [Fact]
    public void AllowsStandaloneMemorySessionsAfterLegacyBackendRemoval()
    {
        WithEnvironment("true", null, null, () =>
        {
            var options = AdminMigrationOptions.FromEnvironment(
                configuredNativeReadsEnabled: false,
                authenticationNativeEnabled: true,
                sharesLegacySessions: false);

            Assert.True(options.NativeReadsEnabled);
        });
    }

    [Fact]
    public void AllowsSharedRedisSessions()
    {
        WithEnvironment("true", null, null, () =>
        {
            var options = AdminMigrationOptions.FromEnvironment(
                configuredNativeReadsEnabled: false,
                authenticationNativeEnabled: true,
                sharesLegacySessions: true);

            Assert.True(options.NativeReadsEnabled);
        });
    }

    [Fact]
    public void OrganizationWritesRequireNativeReads()
    {
        WithEnvironment("false", "true", null, () =>
        {
            var exception = Assert.Throws<InvalidOperationException>(() =>
                AdminMigrationOptions.FromEnvironment(
                    configuredNativeReadsEnabled: false,
                    authenticationNativeEnabled: true,
                    sharesLegacySessions: true));

            Assert.Contains("ADMIN_NATIVE_READS_ENABLED=true", exception.Message);
        });
    }

    [Fact]
    public void EnablesOrganizationWritesWithReadsAndSharedSessions()
    {
        WithEnvironment("true", "true", null, () =>
        {
            var options = AdminMigrationOptions.FromEnvironment(
                configuredNativeReadsEnabled: false,
                authenticationNativeEnabled: true,
                sharesLegacySessions: true);

            Assert.True(options.NativeReadsEnabled);
            Assert.True(options.NativeOrganizationWritesEnabled);
        });
    }

    [Fact]
    public void EnablesAccountBatchesWithReadsAndSharedSessions()
    {
        WithEnvironment("true", null, null, () =>
        {
            var options = AdminMigrationOptions.FromEnvironment(
                configuredNativeReadsEnabled: false,
                authenticationNativeEnabled: true,
                sharesLegacySessions: true);

            Assert.True(options.NativeReadsEnabled);
            Assert.True(options.NativeAccountBatchesEnabled);
        }, accountBatchesEnabled: "true");
    }

    [Fact]
    public void EnablesAdminConfigurationWithReadsAndSharedSessions()
    {
        WithEnvironment("true", null, null, () =>
        {
            var options = AdminMigrationOptions.FromEnvironment(
                configuredNativeReadsEnabled: false,
                authenticationNativeEnabled: true,
                sharesLegacySessions: true);

            Assert.True(options.NativeReadsEnabled);
            Assert.True(options.NativeConfigurationEnabled);
        }, configurationEnabled: "true");
    }

    [Fact]
    public void EnablesNoticeManagementWithReadsAndSharedSessions()
    {
        WithEnvironment("true", null, null, () =>
        {
            var options = AdminMigrationOptions.FromEnvironment(
                configuredNativeReadsEnabled: false,
                authenticationNativeEnabled: true,
                sharesLegacySessions: true);

            Assert.True(options.NativeReadsEnabled);
            Assert.True(options.NativeNoticeManagementEnabled);
        }, noticeManagementEnabled: "true");
    }

    [Fact]
    public void AcceptsLegacyNoticeWritesEnvironmentVariable()
    {
        WithEnvironment("true", null, null, () =>
        {
            var options = AdminMigrationOptions.FromEnvironment(
                configuredNativeReadsEnabled: false,
                authenticationNativeEnabled: true,
                sharesLegacySessions: true);

            Assert.True(options.NativeNoticeManagementEnabled);
        }, legacyNoticeWritesEnabled: "true");
    }

    [Fact]
    public void EnablesCentersWithReadsAndSharedSessions()
    {
        WithEnvironment("true", null, null, () =>
        {
            var options = AdminMigrationOptions.FromEnvironment(
                configuredNativeReadsEnabled: false,
                authenticationNativeEnabled: true,
                sharesLegacySessions: true);

            Assert.True(options.NativeReadsEnabled);
            Assert.True(options.NativeCentersEnabled);
        }, centersEnabled: "true");
    }

    [Fact]
    public void EnablesOperationalReadsWithBaseReadsAndSharedSessions()
    {
        WithEnvironment("true", null, null, () =>
        {
            var options = AdminMigrationOptions.FromEnvironment(
                configuredNativeReadsEnabled: false,
                authenticationNativeEnabled: true,
                sharesLegacySessions: true);

            Assert.True(options.NativeReadsEnabled);
            Assert.True(options.NativeOperationalReadsEnabled);
        }, operationalReadsEnabled: "true");
    }

    [Fact]
    public void CandidateManagementRequiresOperationalReads()
    {
        WithEnvironment("true", null, null, () =>
        {
            var exception = Assert.Throws<InvalidOperationException>(() =>
                AdminMigrationOptions.FromEnvironment(
                    configuredNativeReadsEnabled: false,
                    authenticationNativeEnabled: true,
                    sharesLegacySessions: true));

            Assert.Contains("ADMIN_NATIVE_OPERATIONAL_READS_ENABLED=true", exception.Message);
        }, candidateManagementEnabled: "true");
    }

    [Fact]
    public void EnablesCandidateManagementWithOperationalReadsAndSharedSessions()
    {
        WithEnvironment("true", null, null, () =>
        {
            var options = AdminMigrationOptions.FromEnvironment(
                configuredNativeReadsEnabled: false,
                authenticationNativeEnabled: true,
                sharesLegacySessions: true);

            Assert.True(options.NativeOperationalReadsEnabled);
            Assert.True(options.NativeCandidateManagementEnabled);
        }, operationalReadsEnabled: "true", candidateManagementEnabled: "true");
    }

    [Fact]
    public void RegistrationPaymentWritesRequireOperationalReads()
    {
        WithEnvironment("true", null, null, () =>
        {
            var exception = Assert.Throws<InvalidOperationException>(() =>
                AdminMigrationOptions.FromEnvironment(
                    configuredNativeReadsEnabled: false,
                    authenticationNativeEnabled: true,
                    sharesLegacySessions: true));

            Assert.Contains("ADMIN_NATIVE_OPERATIONAL_READS_ENABLED=true", exception.Message);
        }, registrationPaymentWritesEnabled: "true");
    }

    [Fact]
    public void EnablesRegistrationPaymentWritesWithOperationalReadsAndSharedSessions()
    {
        WithEnvironment("true", null, null, () =>
        {
            var options = AdminMigrationOptions.FromEnvironment(
                configuredNativeReadsEnabled: false,
                authenticationNativeEnabled: true,
                sharesLegacySessions: true);

            Assert.True(options.NativeOperationalReadsEnabled);
            Assert.True(options.NativeRegistrationPaymentWritesEnabled);
        }, operationalReadsEnabled: "true", registrationPaymentWritesEnabled: "true");
    }

    [Fact]
    public void EnablesWorkflowOperationsWithBaseReadsAndSharedSessions()
    {
        WithEnvironment("true", null, null, () =>
        {
            var options = AdminMigrationOptions.FromEnvironment(
                configuredNativeReadsEnabled: false,
                authenticationNativeEnabled: true,
                sharesLegacySessions: true);

            Assert.True(options.NativeReadsEnabled);
            Assert.True(options.NativeWorkflowOperationsEnabled);
        }, workflowOperationsEnabled: "true");
    }

    [Fact]
    public void EnablesExamManagementWithBaseReadsAndSharedSessions()
    {
        WithEnvironment("true", null, null, () =>
        {
            var options = AdminMigrationOptions.FromEnvironment(
                configuredNativeReadsEnabled: false,
                authenticationNativeEnabled: true,
                sharesLegacySessions: true);

            Assert.True(options.NativeReadsEnabled);
            Assert.True(options.NativeExamManagementEnabled);
        }, examManagementEnabled: "true");
    }

    [Fact]
    public void EnablesArrangementsWithBaseReadsAndSharedSessions()
    {
        WithEnvironment("true", null, null, () =>
        {
            var options = AdminMigrationOptions.FromEnvironment(
                configuredNativeReadsEnabled: false,
                authenticationNativeEnabled: true,
                sharesLegacySessions: true);

            Assert.True(options.NativeReadsEnabled);
            Assert.True(options.NativeArrangementsEnabled);
        }, arrangementsEnabled: "true");
    }

    [Fact]
    public void ResultsRequireOperationalReads()
    {
        WithEnvironment("true", null, null, () =>
        {
            var exception = Assert.Throws<InvalidOperationException>(() =>
                AdminMigrationOptions.FromEnvironment(
                    configuredNativeReadsEnabled: false,
                    authenticationNativeEnabled: true,
                    sharesLegacySessions: true));

            Assert.Contains("ADMIN_NATIVE_OPERATIONAL_READS_ENABLED=true", exception.Message);
        }, resultsEnabled: "true");
    }

    [Fact]
    public void EnablesResultsWithOperationalReadsAndSharedSessions()
    {
        WithEnvironment("true", null, null, () =>
        {
            var options = AdminMigrationOptions.FromEnvironment(
                configuredNativeReadsEnabled: false,
                authenticationNativeEnabled: true,
                sharesLegacySessions: true);

            Assert.True(options.NativeOperationalReadsEnabled);
            Assert.True(options.NativeResultsEnabled);
        }, operationalReadsEnabled: "true", resultsEnabled: "true");
    }

    [Fact]
    public void EnablesAdmissionsWithOperationalReadsAndSharedSessions()
    {
        WithEnvironment("true", null, null, () =>
        {
            var options = AdminMigrationOptions.FromEnvironment(
                configuredNativeReadsEnabled: false,
                authenticationNativeEnabled: true,
                sharesLegacySessions: true);

            Assert.True(options.NativeOperationalReadsEnabled);
            Assert.True(options.NativeAdmissionsEnabled);
        }, operationalReadsEnabled: "true", admissionsEnabled: "true");
    }

    private static void WithEnvironment(
        string? nativeReadsEnabled,
        string? nativeOrganizationWritesEnabled,
        string? allowMemory,
        Action test,
        string? accountBatchesEnabled = null,
        string? configurationEnabled = null,
        string? noticeManagementEnabled = null,
        string? legacyNoticeWritesEnabled = null,
        string? centersEnabled = null,
        string? operationalReadsEnabled = null,
        string? candidateManagementEnabled = null,
        string? registrationPaymentWritesEnabled = null,
        string? workflowOperationsEnabled = null,
        string? examManagementEnabled = null,
        string? arrangementsEnabled = null,
        string? resultsEnabled = null,
        string? admissionsEnabled = null)
    {
        var previousNativeReadsEnabled = Environment.GetEnvironmentVariable("ADMIN_NATIVE_READS_ENABLED");
        var previousNativeOrganizationWritesEnabled = Environment.GetEnvironmentVariable("ADMIN_NATIVE_ORGANIZATION_WRITES_ENABLED");
        var previousAccountBatchesEnabled = Environment.GetEnvironmentVariable("ADMIN_NATIVE_ACCOUNT_BATCHES_ENABLED");
        var previousConfigurationEnabled = Environment.GetEnvironmentVariable("ADMIN_NATIVE_CONFIGURATION_ENABLED");
        var previousNoticeManagementEnabled = Environment.GetEnvironmentVariable("ADMIN_NATIVE_NOTICE_MANAGEMENT_ENABLED");
        var previousLegacyNoticeWritesEnabled = Environment.GetEnvironmentVariable("ADMIN_NATIVE_NOTICE_WRITES_ENABLED");
        var previousCentersEnabled = Environment.GetEnvironmentVariable("ADMIN_NATIVE_CENTERS_ENABLED");
        var previousOperationalReadsEnabled = Environment.GetEnvironmentVariable("ADMIN_NATIVE_OPERATIONAL_READS_ENABLED");
        var previousCandidateManagementEnabled = Environment.GetEnvironmentVariable("ADMIN_NATIVE_CANDIDATE_MANAGEMENT_ENABLED");
        var previousRegistrationPaymentWritesEnabled = Environment.GetEnvironmentVariable("ADMIN_NATIVE_REGISTRATION_PAYMENT_WRITES_ENABLED");
        var previousWorkflowOperationsEnabled = Environment.GetEnvironmentVariable("ADMIN_NATIVE_WORKFLOW_OPERATIONS_ENABLED");
        var previousExamManagementEnabled = Environment.GetEnvironmentVariable("ADMIN_NATIVE_EXAM_MANAGEMENT_ENABLED");
        var previousArrangementsEnabled = Environment.GetEnvironmentVariable("ADMIN_NATIVE_ARRANGEMENTS_ENABLED");
        var previousResultsEnabled = Environment.GetEnvironmentVariable("ADMIN_NATIVE_RESULTS_ENABLED");
        var previousAdmissionsEnabled = Environment.GetEnvironmentVariable("ADMIN_NATIVE_ADMISSIONS_ENABLED");
        var previousAllowMemory = Environment.GetEnvironmentVariable("ADMIN_NATIVE_ALLOW_MEMORY");
        try
        {
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_READS_ENABLED", nativeReadsEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_ORGANIZATION_WRITES_ENABLED", nativeOrganizationWritesEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_ACCOUNT_BATCHES_ENABLED", accountBatchesEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_CONFIGURATION_ENABLED", configurationEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_NOTICE_MANAGEMENT_ENABLED", noticeManagementEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_NOTICE_WRITES_ENABLED", legacyNoticeWritesEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_CENTERS_ENABLED", centersEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_OPERATIONAL_READS_ENABLED", operationalReadsEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_CANDIDATE_MANAGEMENT_ENABLED", candidateManagementEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_REGISTRATION_PAYMENT_WRITES_ENABLED", registrationPaymentWritesEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_WORKFLOW_OPERATIONS_ENABLED", workflowOperationsEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_EXAM_MANAGEMENT_ENABLED", examManagementEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_ARRANGEMENTS_ENABLED", arrangementsEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_RESULTS_ENABLED", resultsEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_ADMISSIONS_ENABLED", admissionsEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_ALLOW_MEMORY", allowMemory);
            test();
        }
        finally
        {
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_READS_ENABLED", previousNativeReadsEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_ORGANIZATION_WRITES_ENABLED", previousNativeOrganizationWritesEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_ACCOUNT_BATCHES_ENABLED", previousAccountBatchesEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_CONFIGURATION_ENABLED", previousConfigurationEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_NOTICE_MANAGEMENT_ENABLED", previousNoticeManagementEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_NOTICE_WRITES_ENABLED", previousLegacyNoticeWritesEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_CENTERS_ENABLED", previousCentersEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_OPERATIONAL_READS_ENABLED", previousOperationalReadsEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_CANDIDATE_MANAGEMENT_ENABLED", previousCandidateManagementEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_REGISTRATION_PAYMENT_WRITES_ENABLED", previousRegistrationPaymentWritesEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_WORKFLOW_OPERATIONS_ENABLED", previousWorkflowOperationsEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_EXAM_MANAGEMENT_ENABLED", previousExamManagementEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_ARRANGEMENTS_ENABLED", previousArrangementsEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_RESULTS_ENABLED", previousResultsEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_ADMISSIONS_ENABLED", previousAdmissionsEnabled);
            Environment.SetEnvironmentVariable("ADMIN_NATIVE_ALLOW_MEMORY", previousAllowMemory);
        }
    }
}
