#!/usr/bin/env python3
"""
Security validation tests for configuration loading.
Tests that path traversal and malicious configs are blocked.
"""

import tempfile
import os
import json
from artefact_mcp.core.config_validator import (
    validate_config_path,
    load_json_safely,
    validate_property_mapping_config,
    validate_rfm_thresholds_config,
)


def test_path_traversal_attacks():
    """Test that path traversal attacks are blocked."""
    print("\n=== Test 1: Path Traversal Prevention ===")

    # Attack: Try to read /etc/passwd
    is_valid, error = validate_config_path("/etc/passwd")
    assert not is_valid
    assert "must be .json" in error
    print("✓ Blocked /etc/passwd (not .json)")

    # Attack: Try relative path
    is_valid, error = validate_config_path("../../../etc/passwd.json")
    assert not is_valid
    assert "absolute" in error
    print("✓ Blocked relative path")

    # Attack: Try non-existent file
    is_valid, error = validate_config_path("/tmp/nonexistent_file_12345.json")
    assert not is_valid
    assert "does not exist" in error
    print("✓ Blocked non-existent file")

    print("✓ Path traversal prevention works")


def test_file_size_limits():
    """Test that large files are rejected."""
    print("\n=== Test 2: File Size Limits ===")

    with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
        # Create a 2MB file (over 1MB limit)
        large_data = {"data": "x" * 2_000_000}
        json.dump(large_data, f)
        large_file = f.name

    try:
        config, error = load_json_safely(large_file)
        assert config is None
        assert error is not None
        assert "too large" in error or "exceeds size" in error
        print(f"✓ Blocked large file: {error}")
    finally:
        os.unlink(large_file)

    print("✓ File size limits work")


def test_invalid_json():
    """Test that malformed JSON is rejected."""
    print("\n=== Test 3: Invalid JSON Detection ===")

    with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
        f.write("{invalid json content")
        invalid_file = f.name

    try:
        config, error = load_json_safely(invalid_file)
        assert config is None
        assert "Invalid JSON" in error
        print(f"✓ Blocked invalid JSON: {error}")
    finally:
        os.unlink(invalid_file)

    print("✓ Invalid JSON detection works")


def test_property_mapping_validation():
    """Test property mapping configuration validation."""
    print("\n=== Test 4: Property Mapping Validation ===")

    # Test 1: Valid config
    valid_config = {
        "tech_stack": "technologies",
        "growth_signals": ["hiring", "funding"],
        "content_engagement": "page_views"
    }
    is_valid, errors = validate_property_mapping_config(valid_config)
    assert is_valid
    assert len(errors) == 0
    print("✓ Valid config passes")

    # Test 2: Unexpected keys
    invalid_config = {
        "malicious_key": "value",
        "tech_stack": "technologies"
    }
    is_valid, errors = validate_property_mapping_config(invalid_config)
    assert not is_valid
    assert any("Unexpected" in e for e in errors)
    print(f"✓ Blocked unexpected keys: {errors[0]}")

    # Test 3: Wrong type
    invalid_config = {
        "tech_stack": 123  # Should be string
    }
    is_valid, errors = validate_property_mapping_config(invalid_config)
    assert not is_valid
    assert any("must be a string" in e for e in errors)
    print(f"✓ Blocked wrong type: {errors[0]}")

    # Test 4: Too many growth signals
    invalid_config = {
        "growth_signals": ["signal_" + str(i) for i in range(100)]  # Max 50
    }
    is_valid, errors = validate_property_mapping_config(invalid_config)
    assert not is_valid
    assert any("cannot have more than 50" in e for e in errors)
    print(f"✓ Blocked excessive array: {errors[0]}")

    print("✓ Property mapping validation works")


def test_rfm_thresholds_validation():
    """Test RFM thresholds configuration validation."""
    print("\n=== Test 5: RFM Thresholds Validation ===")

    # Test 1: Valid config
    valid_config = {
        "recency_days": [30, 90, 180, 365],
        "recency_scores": [5, 4, 3, 2, 1],
        "frequency_counts": [10, 5, 3, 2],
        "frequency_scores": [5, 4, 3, 2, 1]
    }
    is_valid, errors = validate_rfm_thresholds_config(valid_config)
    assert is_valid
    assert len(errors) == 0
    print("✓ Valid config passes")

    # Test 2: Recency days not ascending
    invalid_config = {
        "recency_days": [365, 180, 90, 30],  # Wrong order!
        "recency_scores": [5, 4, 3, 2, 1]
    }
    is_valid, errors = validate_rfm_thresholds_config(invalid_config)
    assert not is_valid
    assert any("ascending" in e for e in errors)
    print(f"✓ Blocked wrong order: {errors[0]}")

    # Test 3: Frequency counts not descending
    invalid_config = {
        "frequency_counts": [2, 5, 10],  # Should be descending
        "frequency_scores": [5, 4, 3, 2]
    }
    is_valid, errors = validate_rfm_thresholds_config(invalid_config)
    assert not is_valid
    assert any("descending" in e for e in errors)
    print(f"✓ Blocked wrong order: {errors[0]}")

    # Test 4: Mismatched array lengths
    invalid_config = {
        "recency_days": [30, 90, 180],
        "recency_scores": [5, 4, 3]  # Should have 4 elements (days + 1)
    }
    is_valid, errors = validate_rfm_thresholds_config(invalid_config)
    assert not is_valid
    assert any("one more element" in e for e in errors)
    print(f"✓ Blocked mismatched lengths: {errors[0]}")

    # Test 5: Invalid monetary method
    invalid_config = {
        "monetary_method": "invalid_method"
    }
    is_valid, errors = validate_rfm_thresholds_config(invalid_config)
    assert not is_valid
    assert any("percentile" in e or "fixed" in e for e in errors)
    print(f"✓ Blocked invalid method: {errors[0]}")

    print("✓ RFM thresholds validation works")


def test_valid_config_loading():
    """Test that valid configurations load successfully."""
    print("\n=== Test 6: Valid Config Loading ===")

    # Create valid property mapping config
    valid_config = {
        "tech_stack": "technologies_used",
        "growth_signals": ["hiring_count", "funding_amount"],
        "content_engagement": "page_views"
    }

    with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
        json.dump(valid_config, f)
        config_file = f.name

    try:
        config, error = load_json_safely(config_file)
        assert config is not None
        assert error is None
        assert config["tech_stack"] == "technologies_used"
        print("✓ Valid config loaded successfully")

        # Validate structure
        is_valid, errors = validate_property_mapping_config(config)
        assert is_valid
        assert len(errors) == 0
        print("✓ Valid config passed validation")
    finally:
        os.unlink(config_file)

    print("✓ Valid config loading works")


if __name__ == "__main__":
    print("Security Validation Tests")
    print("=" * 50)

    test_path_traversal_attacks()
    test_file_size_limits()
    test_invalid_json()
    test_property_mapping_validation()
    test_rfm_thresholds_validation()
    test_valid_config_loading()

    print("\n" + "=" * 50)
    print("✅ All security tests passed!")
    print("\nConfiguration loading is secure:")
    print("  ✓ Path traversal blocked")
    print("  ✓ File size limits enforced")
    print("  ✓ Invalid JSON rejected")
    print("  ✓ Configuration structure validated")
    print("  ✓ Array ordering checked")
    print("  ✓ Type validation enforced")
