import pytest

from phoenix.auth import (
    validate_email_format,
    validate_password_format,
)


def test_validate_email_format_does_not_raise_on_valid_format() -> None:
    validate_email_format("user@domain.com")


@pytest.mark.parametrize(
    "email",
    (
        pytest.param("userdomain.com", id="missing-@"),
        pytest.param("user@domain", id="missing-top-level-domain-name"),
        pytest.param("user@domain.", id="empty-top-level-domain-name"),
        pytest.param("user@.com", id="missing-domain-name"),
        pytest.param("@domain.com", id="missing-username"),
        pytest.param("user @domain.com", id="username-contains-space"),
        pytest.param("user@do main.com", id="domain-name-contains-space"),
        pytest.param("user@domain.c om", id="top-level-domain-name-contains-space"),
        pytest.param(" user@domain.com", id="leading-space"),
        pytest.param("user@domain.com ", id="trailing-space"),
        pytest.param(" user@domain.com", id="leading-space"),
        pytest.param("\nuser@domain.com ", id="leading-newline"),
        pytest.param("user@domain.com\n", id="trailing-newline"),
    ),
)
def test_validate_email_format_raises_on_invalid_format(email: str) -> None:
    with pytest.raises(ValueError):
        validate_email_format(email)


def test_validate_password_format_does_not_raise_on_valid_format() -> None:
    validate_password_format("Password1234!")


@pytest.mark.parametrize(
    "password",
    (
        pytest.param("", id="empty"),
        pytest.param("pass word", id="contains-space"),
        pytest.param("pass\nword", id="contains-newline"),
        pytest.param("password\n", id="trailing-newline"),
        pytest.param("P@ßwø®∂!ñ", id="contains-non-ascii-chars"),
        pytest.param("안녕하세요", id="korean"),
        pytest.param("🚀", id="emoji"),
    ),
)
def test_validate_password_format_raises_on_invalid_format(password: str) -> None:
    with pytest.raises(ValueError):
        validate_password_format(password)


class TestEmailSanitization:
    """Test the sanitize_email function."""

    def test_sanitize_email_lowercase(self) -> None:
        """Test that sanitize_email converts uppercase to lowercase."""
        from phoenix.auth import sanitize_email

        test_cases = [
            ("test@example.com", "test@example.com"),  # already lowercase
            ("TEST@EXAMPLE.COM", "test@example.com"),  # all uppercase
            ("Test@Example.Com", "test@example.com"),  # mixed case
            ("USER@DOMAIN.ORG", "user@domain.org"),  # different domain
        ]

        for input_email, expected in test_cases:
            result = sanitize_email(input_email)
            assert result == expected, (
                f"sanitize_email('{input_email}') should return '{expected}', but got '{result}'"
            )

    def test_sanitize_email_trim_whitespace(self) -> None:
        """Test that sanitize_email trims whitespace."""
        from phoenix.auth import sanitize_email

        test_cases = [
            ("  test@example.com  ", "test@example.com"),
            ("\tuser@domain.org\n", "user@domain.org"),
            ("   UPPER@CASE.COM   ", "upper@case.com"),
            (" \t MIXED@WHITESPACE.NET \n ", "mixed@whitespace.net"),
        ]

        for input_email, expected in test_cases:
            result = sanitize_email(input_email)
            assert result == expected, (
                f"sanitize_email('{repr(input_email)}') should return '{expected}', "
                f"but got '{result}'"
            )

    def test_sanitize_email_combined(self) -> None:
        """Test that sanitize_email handles both case and whitespace."""
        from phoenix.auth import sanitize_email

        # Test comprehensive sanitization
        messy_email = "  \t TEST.USER@EXAMPLE.COM \n  "
        expected = "test.user@example.com"
        result = sanitize_email(messy_email)

        assert result == expected, (
            f"sanitize_email should handle both case and whitespace: "
            f"expected '{expected}', but got '{result}'"
        )

    def test_sanitize_email_empty_and_edge_cases(self) -> None:
        """Test edge cases for sanitize_email."""
        from phoenix.auth import sanitize_email

        test_cases = [
            ("", ""),  # empty string
            ("   ", ""),  # only whitespace
            ("a@b.c", "a@b.c"),  # minimal valid email
            ("  A@B.C  ", "a@b.c"),  # minimal with whitespace and case
        ]

        for input_email, expected in test_cases:
            result = sanitize_email(input_email)
            assert result == expected, (
                f"sanitize_email('{repr(input_email)}') should return '{expected}', "
                f"but got '{result}'"
            )


class TestPasswordPolicy:
    """Test the configurable password policy."""

    def test_default_policy_accepts_short_password(self) -> None:
        """Default policy only requires 4 characters."""
        validate_password_format("abcd")

    def test_default_policy_rejects_too_short(self) -> None:
        """Default policy rejects passwords under 4 characters."""
        with pytest.raises(ValueError):
            validate_password_format("abc")

    def test_strong_policy_accepts_valid_password(self) -> None:
        """Strong policy accepts a password meeting all requirements."""
        from unittest import mock

        with mock.patch("phoenix.config.get_env_enable_strong_password_policy", return_value=True):
            validate_password_format("StrongPass1!")

    def test_strong_policy_rejects_short_password(self) -> None:
        """Strong policy rejects passwords under 12 characters."""
        from unittest import mock

        with mock.patch("phoenix.config.get_env_enable_strong_password_policy", return_value=True):
            with pytest.raises(ValueError, match="at least 12 characters"):
                validate_password_format("Short1!")

    def test_strong_policy_rejects_missing_uppercase(self) -> None:
        """Strong policy rejects passwords without uppercase letters."""
        from unittest import mock

        with mock.patch("phoenix.config.get_env_enable_strong_password_policy", return_value=True):
            with pytest.raises(ValueError, match="uppercase"):
                validate_password_format("strongpass12!")

    def test_strong_policy_rejects_missing_lowercase(self) -> None:
        """Strong policy rejects passwords without lowercase letters."""
        from unittest import mock

        with mock.patch("phoenix.config.get_env_enable_strong_password_policy", return_value=True):
            with pytest.raises(ValueError, match="lowercase"):
                validate_password_format("STRONGPASS12!")

    def test_strong_policy_rejects_missing_digit(self) -> None:
        """Strong policy rejects passwords without digits."""
        from unittest import mock

        with mock.patch("phoenix.config.get_env_enable_strong_password_policy", return_value=True):
            with pytest.raises(ValueError, match="digit"):
                validate_password_format("StrongPasswd!")

    def test_strong_policy_rejects_missing_special_char(self) -> None:
        """Strong policy rejects passwords without special characters."""
        from unittest import mock

        with mock.patch("phoenix.config.get_env_enable_strong_password_policy", return_value=True):
            with pytest.raises(ValueError, match="special character"):
                validate_password_format("StrongPass123")
