from unittest import mock

from tests.providers.azure.azure_fixtures import DOMAIN, set_mocked_azure_provider

CHECK_MODULE = (
    "prowler.providers.azure.services.entra."
    "entra_authentication_methods_policy_strong_auth_enforced."
    "entra_authentication_methods_policy_strong_auth_enforced"
)


class Test_entra_authentication_methods_policy_strong_auth_enforced:
    def test_entra_no_tenants(self):
        entra_client = mock.MagicMock

        with (
            mock.patch(
                "prowler.providers.common.provider.Provider.get_global_provider",
                return_value=set_mocked_azure_provider(),
            ),
            mock.patch(f"{CHECK_MODULE}.entra_client", new=entra_client),
        ):
            from prowler.providers.azure.services.entra.entra_authentication_methods_policy_strong_auth_enforced.entra_authentication_methods_policy_strong_auth_enforced import (
                entra_authentication_methods_policy_strong_auth_enforced,
            )

            entra_client.authentication_methods_policy = {}

            check = entra_authentication_methods_policy_strong_auth_enforced()
            result = check.execute()
            assert len(result) == 0

    def test_entra_policy_none(self):
        entra_client = mock.MagicMock

        with (
            mock.patch(
                "prowler.providers.common.provider.Provider.get_global_provider",
                return_value=set_mocked_azure_provider(),
            ),
            mock.patch(f"{CHECK_MODULE}.entra_client", new=entra_client),
        ):
            from prowler.providers.azure.services.entra.entra_authentication_methods_policy_strong_auth_enforced.entra_authentication_methods_policy_strong_auth_enforced import (
                entra_authentication_methods_policy_strong_auth_enforced,
            )

            entra_client.authentication_methods_policy = {DOMAIN: None}

            check = entra_authentication_methods_policy_strong_auth_enforced()
            result = check.execute()
            assert len(result) == 0

    def test_entra_registration_enabled_strong_method_enabled(self):
        entra_client = mock.MagicMock

        with (
            mock.patch(
                "prowler.providers.common.provider.Provider.get_global_provider",
                return_value=set_mocked_azure_provider(),
            ),
            mock.patch(f"{CHECK_MODULE}.entra_client", new=entra_client),
        ):
            from prowler.providers.azure.services.entra.entra_authentication_methods_policy_strong_auth_enforced.entra_authentication_methods_policy_strong_auth_enforced import (
                entra_authentication_methods_policy_strong_auth_enforced,
            )
            from prowler.providers.azure.services.entra.entra_service import (
                AuthMethodConfig,
                AuthMethodsPolicy,
            )

            policy = AuthMethodsPolicy(
                id="authMethodsPolicy",
                registration_enforcement_state="enabled",
                method_configurations=[
                    AuthMethodConfig(
                        id="MicrosoftAuthenticator",
                        method_name="microsoftAuthenticator",
                        state="enabled",
                    ),
                    AuthMethodConfig(id="Sms", method_name="sms", state="enabled"),
                ],
            )
            entra_client.authentication_methods_policy = {DOMAIN: policy}

            check = entra_authentication_methods_policy_strong_auth_enforced()
            result = check.execute()
            assert len(result) == 1
            assert result[0].status == "PASS"
            assert result[0].resource_name == "Authentication Methods Policy"
            assert result[0].resource_id == "authMethodsPolicy"
            assert "is enforced" in result[0].status_extended
            assert "microsoftAuthenticator" in result[0].status_extended

    def test_entra_registration_disabled_no_strong_methods(self):
        entra_client = mock.MagicMock

        with (
            mock.patch(
                "prowler.providers.common.provider.Provider.get_global_provider",
                return_value=set_mocked_azure_provider(),
            ),
            mock.patch(f"{CHECK_MODULE}.entra_client", new=entra_client),
        ):
            from prowler.providers.azure.services.entra.entra_authentication_methods_policy_strong_auth_enforced.entra_authentication_methods_policy_strong_auth_enforced import (
                entra_authentication_methods_policy_strong_auth_enforced,
            )
            from prowler.providers.azure.services.entra.entra_service import (
                AuthMethodConfig,
                AuthMethodsPolicy,
            )

            policy = AuthMethodsPolicy(
                id="authMethodsPolicy",
                registration_enforcement_state="disabled",
                method_configurations=[
                    AuthMethodConfig(id="Sms", method_name="sms", state="enabled"),
                    AuthMethodConfig(id="Voice", method_name="voice", state="enabled"),
                ],
            )
            entra_client.authentication_methods_policy = {DOMAIN: policy}

            check = entra_authentication_methods_policy_strong_auth_enforced()
            result = check.execute()
            assert len(result) == 1
            assert result[0].status == "FAIL"
            assert "is not enforced" in result[0].status_extended
            assert "registration campaign is not enabled" in result[0].status_extended
            assert "no strong authentication methods" in result[0].status_extended

    def test_entra_registration_disabled_strong_method_enabled(self):
        entra_client = mock.MagicMock

        with (
            mock.patch(
                "prowler.providers.common.provider.Provider.get_global_provider",
                return_value=set_mocked_azure_provider(),
            ),
            mock.patch(f"{CHECK_MODULE}.entra_client", new=entra_client),
        ):
            from prowler.providers.azure.services.entra.entra_authentication_methods_policy_strong_auth_enforced.entra_authentication_methods_policy_strong_auth_enforced import (
                entra_authentication_methods_policy_strong_auth_enforced,
            )
            from prowler.providers.azure.services.entra.entra_service import (
                AuthMethodConfig,
                AuthMethodsPolicy,
            )

            policy = AuthMethodsPolicy(
                id="authMethodsPolicy",
                registration_enforcement_state="disabled",
                method_configurations=[
                    AuthMethodConfig(id="Fido2", method_name="fido2", state="enabled"),
                ],
            )
            entra_client.authentication_methods_policy = {DOMAIN: policy}

            check = entra_authentication_methods_policy_strong_auth_enforced()
            result = check.execute()
            # Strong method present but registration campaign off -> not enforced
            assert len(result) == 1
            assert result[0].status == "FAIL"
            assert "registration campaign is not enabled" in result[0].status_extended
            assert "no strong authentication methods" not in result[0].status_extended

    def test_entra_multiple_strong_methods(self):
        entra_client = mock.MagicMock

        with (
            mock.patch(
                "prowler.providers.common.provider.Provider.get_global_provider",
                return_value=set_mocked_azure_provider(),
            ),
            mock.patch(f"{CHECK_MODULE}.entra_client", new=entra_client),
        ):
            from prowler.providers.azure.services.entra.entra_authentication_methods_policy_strong_auth_enforced.entra_authentication_methods_policy_strong_auth_enforced import (
                entra_authentication_methods_policy_strong_auth_enforced,
            )
            from prowler.providers.azure.services.entra.entra_service import (
                AuthMethodConfig,
                AuthMethodsPolicy,
            )

            policy = AuthMethodsPolicy(
                id="authMethodsPolicy",
                registration_enforcement_state="enabled",
                method_configurations=[
                    AuthMethodConfig(
                        id="MicrosoftAuthenticator",
                        method_name="microsoftAuthenticator",
                        state="enabled",
                    ),
                    AuthMethodConfig(id="Fido2", method_name="fido2", state="enabled"),
                    AuthMethodConfig(
                        id="x509", method_name="x509Certificate", state="enabled"
                    ),
                ],
            )
            entra_client.authentication_methods_policy = {DOMAIN: policy}

            check = entra_authentication_methods_policy_strong_auth_enforced()
            result = check.execute()
            assert len(result) == 1
            assert result[0].status == "PASS"
            assert "microsoftAuthenticator" in result[0].status_extended
            assert "fido2" in result[0].status_extended
