"""Security Tests for GEO-SEO Optimizer.

Agent: Agent-3 (安全测试专家)
Scope: SQL注入、XSS、输入验证、API密钥安全
"""

from pathlib import Path

import pytest

from src.utils.validators import validate_content_length, validate_keyword


@pytest.mark.security
def test_sql_injection_in_keyword():
    """安全: 关键词输入SQL注入防护."""
    malicious = "'; DROP TABLE metrics; --"
    is_valid, error = validate_keyword(malicious)
    assert not is_valid, "SQL注入应被阻止"


@pytest.mark.security
def test_xss_in_content():
    """安全: 内容XSS攻击防护."""
    malicious = "<script>alert('xss')</script>"
    is_valid, error = validate_keyword(malicious)
    assert not is_valid, "XSS应被阻止"


@pytest.mark.security
def test_path_traversal_in_cache():
    """安全: 缓存路径遍历防护.

    Scenario:
        - 关键词包含 ../ 等路径遍历字符
        - 应被安全处理
    """
    path_traversal_attempts = [
        "../../../etc/passwd",
        "..\\..\\windows\\system32\\config\\sam",
        "keyword/../../../secret",
        "..%2f..%2f..%2fetc%2fpasswd",
    ]

    for attempt in path_traversal_attempts:
        # Keywords with path traversal should be rejected
        is_valid, error = validate_keyword(attempt)
        assert not is_valid, f"路径遍历尝试应被阻止: {attempt}"


@pytest.mark.security
def test_api_key_security():
    """安全: API密钥安全存储验证.

    Checks:
        - .env 文件在 .gitignore 中
        - 密钥不被日志记录
        - 密钥不被序列化
    """
    # Check .env is in .gitignore
    gitignore_path = Path(".gitignore")
    if gitignore_path.exists():
        gitignore_content = gitignore_path.read_text()
        assert ".env" in gitignore_content, ".env 应被添加到 .gitignore"

    # Check API key patterns are not in code
    # (This is a basic check, real security audit would need more)
    dangerous_patterns = [
        'api_key = "',
        "api_key='",
        'apikey = "',
        "apikey='",
        'secret = "',
        "secret='",
        'password = "',
        "password='",
    ]

    src_dir = Path("src")
    for py_file in src_dir.rglob("*.py"):
        content = py_file.read_text()
        for pattern in dangerous_patterns:
            # Check for dangerous pattern but allow placeholder examples
            if (
                pattern in content.lower()
                and "example" not in content.lower()
                and "placeholder" not in content.lower()
            ):
                pytest.fail(f"可能的硬编码密钥在 {py_file}: {pattern}")


@pytest.mark.security
def test_input_boundary_conditions():
    """安全: 输入边界条件测试.

    Cases:
        - 超长内容 (100KB+)
        - 特殊Unicode字符
        - 空值/Null
        - 嵌套对象
    """
    # Test 100KB+ content
    huge_content = "x" * (100 * 1024 + 1)
    is_valid, error = validate_content_length(huge_content, max_length=50000)
    assert not is_valid, "超长内容应被拒绝"

    # Test special Unicode characters
    unicode_attempts = [
        "test\x00",  # Null byte
        "test\x01",  # Control character
        "\u202e\u202d",  # Right-to-left override
        "test\uffff",  # Non-character
    ]

    for attempt in unicode_attempts:
        # Should either validate or handle gracefully
        try:
            validate_keyword(attempt)
        except Exception as e:
            pytest.fail(f"Unicode字符处理异常: {attempt!r} - {e}")

    # Test None/Null
    is_valid, error = validate_keyword("")
    assert not is_valid, "空字符串应被拒绝"
