"""
验证工具与schema守卫单元测试

覆盖：
- validate_phone / normalize_phone / validate_email
- schema_guard: normalize_environment / assert_auto_create_schema_allowed
"""

import pytest

from packages.adapters.sqlalchemy_impl.schema_guard import (
    BLOCKED_AUTO_CREATE_ENVIRONMENTS,
    assert_auto_create_schema_allowed,
    normalize_environment,
)
from packages.application.auth.verification_code_service import (
    normalize_phone,
    validate_email,
    validate_phone,
)

# ============================================================
# validate_phone
# ============================================================


class TestValidatePhone:
    """validate_phone 手机号校验"""

    def test_valid_11digit_mainland(self):
        ok, msg = validate_phone("13812345678")
        assert ok is True
        assert msg == ""

    def test_valid_with_plus86_prefix(self):
        ok, msg = validate_phone("+8613812345678")
        assert ok is True
        assert msg == ""

    def test_valid_13x_prefix(self):
        ok, _ = validate_phone("13012345678")
        assert ok is True

    def test_valid_19x_prefix(self):
        ok, _ = validate_phone("19912345678")
        assert ok is True

    def test_valid_17x_prefix(self):
        ok, _ = validate_phone("17612345678")
        assert ok is True

    def test_empty_returns_false(self):
        ok, msg = validate_phone("")
        assert ok is False
        assert "不能为空" in msg

    def test_whitespace_stripped_empty(self):
        ok, msg = validate_phone("   ")
        assert ok is False
        assert "不能为空" in msg

    def test_too_short_returns_false(self):
        ok, msg = validate_phone("138123456")  # 9位
        assert ok is False
        assert "格式不正确" in msg

    def test_too_long_returns_false(self):
        ok, msg = validate_phone("138123456789")  # 12位
        assert ok is False
        assert "格式不正确" in msg

    def test_invalid_prefix_12x(self):
        ok, _ = validate_phone("12312345678")
        assert ok is False

    def test_invalid_prefix_11x(self):
        ok, _ = validate_phone("11012345678")
        assert ok is False

    def test_contains_letters(self):
        ok, _ = validate_phone("138abc45678")
        assert ok is False

    def test_contains_spaces_in_middle(self):
        ok, _ = validate_phone("138 1234 5678")
        assert ok is False

    def test_whitespace_stripped_valid(self):
        ok, _ = validate_phone("  13812345678  ")
        assert ok is True

    def test_plus86_with_spaces(self):
        ok, _ = validate_phone(" +8613812345678 ")
        assert ok is True


# ============================================================
# normalize_phone
# ============================================================


class TestNormalizePhone:
    """normalize_phone 手机号标准化"""

    def test_plain_number_unchanged(self):
        assert normalize_phone("13812345678") == "13812345678"

    def test_plus86_prefix_removed(self):
        assert normalize_phone("+8613812345678") == "13812345678"

    def test_whitespace_stripped(self):
        assert normalize_phone("  13812345678  ") == "13812345678"

    def test_plus86_with_spaces(self):
        assert normalize_phone(" +8613900001111 ") == "13900001111"

    def test_empty_string(self):
        assert normalize_phone("") == ""

    def test_only_plus86(self):
        assert normalize_phone("+86") == ""


# ============================================================
# validate_email
# ============================================================


class TestValidateEmail:
    """validate_email 邮箱校验"""

    def test_valid_simple(self):
        ok, msg = validate_email("user@example.com")
        assert ok is True
        assert msg == ""

    def test_valid_with_subdomain(self):
        ok, _ = validate_email("user@mail.example.com")
        assert ok is True

    def test_valid_with_plus_suffix(self):
        ok, _ = validate_email("user+tag@example.com")
        assert ok is True

    def test_valid_with_dots_in_local(self):
        ok, _ = validate_email("user.name@example.com")
        assert ok is True

    def test_valid_with_underscore(self):
        ok, _ = validate_email("user_name@example.com")
        assert ok is True

    def test_valid_with_hyphen(self):
        ok, _ = validate_email("user-name@example.com")
        assert ok is True

    def test_valid_uppercase(self):
        ok, _ = validate_email("User.Name@Example.COM")
        assert ok is True

    def test_empty_returns_false(self):
        ok, msg = validate_email("")
        assert ok is False
        assert "不能为空" in msg

    def test_whitespace_only_returns_false(self):
        ok, msg = validate_email("   ")
        assert ok is False
        assert "不能为空" in msg

    def test_no_at_sign(self):
        ok, _ = validate_email("userexample.com")
        assert ok is False

    def test_no_domain(self):
        ok, _ = validate_email("user@")
        assert ok is False

    def test_no_local_part(self):
        ok, _ = validate_email("@example.com")
        assert ok is False

    def test_no_dot_in_domain(self):
        ok, _ = validate_email("user@example")
        assert ok is False

    def test_single_letter_tld(self):
        ok, _ = validate_email("user@example.c")
        assert ok is False

    def test_whitespace_stripped(self):
        ok, _ = validate_email("  user@example.com  ")
        assert ok is True

    def test_special_chars_percent(self):
        ok, _ = validate_email("user%name@example.com")
        assert ok is True


# ============================================================
# normalize_environment
# ============================================================


class TestNormalizeEnvironment:
    """normalize_environment 环境名标准化"""

    def test_development(self):
        assert normalize_environment("development") == "development"

    def test_production(self):
        assert normalize_environment("production") == "production"

    def test_staging(self):
        assert normalize_environment("staging") == "staging"

    def test_none_defaults_to_development(self):
        assert normalize_environment(None) == "development"

    def test_empty_defaults_to_development(self):
        assert normalize_environment("") == "development"

    def test_uppercase_lowered(self):
        assert normalize_environment("PRODUCTION") == "production"

    def test_mixed_case(self):
        assert normalize_environment("Staging") == "staging"

    def test_whitespace_stripped(self):
        assert normalize_environment("  production  ") == "production"

    def test_custom_env_name(self):
        assert normalize_environment("custom-env") == "custom-env"


# ============================================================
# assert_auto_create_schema_allowed
# ============================================================


class TestAssertAutoCreateSchemaAllowed:
    """assert_auto_create_schema_allowed 安全守卫"""

    def test_development_enabled_ok(self):
        # 不抛异常
        assert_auto_create_schema_allowed("development", enabled=True)

    def test_development_disabled_ok(self):
        assert_auto_create_schema_allowed("development", enabled=False)

    def test_staging_enabled_raises(self):
        with pytest.raises(RuntimeError, match="forbidden"):
            assert_auto_create_schema_allowed("staging", enabled=True)

    def test_production_enabled_raises(self):
        with pytest.raises(RuntimeError, match="forbidden"):
            assert_auto_create_schema_allowed("production", enabled=True)

    def test_staging_disabled_ok(self):
        assert_auto_create_schema_allowed("staging", enabled=False)

    def test_production_disabled_ok(self):
        assert_auto_create_schema_allowed("production", enabled=False)

    def test_none_env_enabled_ok(self):
        # None → development → 允许
        assert_auto_create_schema_allowed(None, enabled=True)

    def test_uppercase_still_blocked(self):
        with pytest.raises(RuntimeError):
            assert_auto_create_schema_allowed("PRODUCTION", enabled=True)

    def test_whitespace_staging_blocked(self):
        with pytest.raises(RuntimeError):
            assert_auto_create_schema_allowed("  staging  ", enabled=True)

    def test_custom_env_enabled_ok(self):
        assert_auto_create_schema_allowed("test-env", enabled=True)

    def test_blocked_envs_constant(self):
        assert "staging" in BLOCKED_AUTO_CREATE_ENVIRONMENTS
        assert "production" in BLOCKED_AUTO_CREATE_ENVIRONMENTS
