"""
Architecture Compliance Tests
Ensures the Intelligence Architecture is properly followed:
Services → Intelligence API (build config) → EngineClient (execute) → Engine
"""
import re
import ast
from pathlib import Path


def test_no_rapidfuzz_in_services():
    """Ensure no direct rapidfuzz usage outside core/"""
    services_dir = Path(__file__).parent.parent / "src/fmatch/saas/services"
    
    violations = []
    for py_file in services_dir.rglob("*.py"):
        if py_file.suffix != '.py':
            continue
            
        content = py_file.read_text()
        
        # Check for rapidfuzz imports
        if 'from rapidfuzz' in content or 'import rapidfuzz' in content:
            violations.append(str(py_file.relative_to(services_dir)))
    
    assert not violations, f"Services using rapidfuzz directly: {violations}. Should use engine_client instead."


def test_services_extend_base_intelligent():
    """Ensure all intelligent services extend BaseIntelligentService"""
    services_dir = Path(__file__).parent.parent / "src/fmatch/saas/services"
    
    service_files = [
        "l2a_service_intelligent.py",
        "dedupe_service_intelligent.py",
        "dedupe_service_intelligent_v2.py"
    ]
    
    for service_file in service_files:
        file_path = services_dir / service_file
        if not file_path.exists():
            continue
            
        content = file_path.read_text()
        
        # Check for BaseIntelligentService inheritance
        assert "BaseIntelligentService" in content, f"{service_file} should extend BaseIntelligentService"
        
        # Use AST to verify inheritance
        try:
            tree = ast.parse(content)
            for node in ast.walk(tree):
                if isinstance(node, ast.ClassDef):
                    # Check if any class inherits from BaseIntelligentService
                    for base in node.bases:
                        if isinstance(base, ast.Name) and base.id == "BaseIntelligentService":
                            break
                    else:
                        continue
                    break
            else:
                assert False, f"{service_file} has no class extending BaseIntelligentService"
        except SyntaxError:
            pass  # Skip syntax errors


def test_frontend_no_local_configs():
    """Ensure frontend doesn't build configs locally"""
    frontend_dir = Path(__file__).parent.parent / "frontend/matching_app/src"
    
    # Check QuickMatchMain.jsx doesn't contain manual configuration
    quickmatch_file = frontend_dir / "pages/QuickMatch/QuickMatchMain.jsx"
    if quickmatch_file.exists():
        content = quickmatch_file.read_text()
        
        # These patterns indicate manual configuration building
        forbidden_patterns = [
            r"threshold\s*[=:]\s*\d+",  # threshold = 85 or threshold: 85
            r"mappings\s*[=:]\s*\[",    # mappings = [ or mappings: [
            r"setThreshold\(",           # setThreshold(
            r"setMappings\(",            # setMappings(
            r"handleAddMapping",         # handleAddMapping function
            r"handleRemoveMapping",      # handleRemoveMapping function
            r"suggestMappings\(",        # Direct mapping suggestion
            r"calculateNameSimilarity",  # Local similarity calculation
            r"processColumnNameForFuzzy" # Local column processing
        ]
        
        violations = []
        for pattern in forbidden_patterns:
            if re.search(pattern, content):
                violations.append(pattern)
        
        # Allow some violations if they're in backup files or comments
        filtered_violations = []
        for v in violations:
            # Count actual occurrences (not in comments)
            lines = content.split('\n')
            real_occurrences = 0
            for line in lines:
                if re.search(v, line) and not line.strip().startswith('//'):
                    real_occurrences += 1
            if real_occurrences > 0:
                filtered_violations.append(v)
        
        assert not filtered_violations, f"QuickMatchMain.jsx contains manual configuration: {filtered_violations}"


def test_correlation_id_in_intelligence_responses():
    """Ensure Intelligence API returns correlation_id in responses"""
    intelligence_file = Path(__file__).parent.parent / "src/fmatch/saas/api/v2/intelligence.py"
    
    if intelligence_file.exists():
        content = intelligence_file.read_text()
        
        # Check that correlation_id is being generated and returned
        assert "correlation_id" in content, "Intelligence API should generate correlation_id"
        assert "uuid4()" in content or "uuid.uuid4()" in content, "Should use uuid4 for correlation_id"
        
        # Check that it's stored in Redis
        assert "correlation:" in content, "Should store correlation_id in Redis with 'correlation:' prefix"


def test_jobs_validates_correlation_id():
    """Ensure Jobs API validates correlation_id when executing"""
    jobs_file = Path(__file__).parent.parent / "src/fmatch/saas/api/v2/jobs.py"
    
    if jobs_file.exists():
        content = jobs_file.read_text()
        
        # Check for correlation_id validation in execute endpoint
        assert "correlation_id" in content, "Jobs API should check for correlation_id"
        assert "correlation:" in content, "Should look up correlation_id in Redis"


def test_engine_client_accepts_configs():
    """Ensure engine_client accepts configuration objects directly"""
    engine_client_file = Path(__file__).parent.parent / "src/fmatch/saas/services/engine_client.py"
    
    if engine_client_file.exists():
        content = engine_client_file.read_text()
        
        # Engine client should have match and dedupe methods
        assert "def match(" in content or "async def match(" in content, "Should have match method"
        assert "def dedupe(" in content or "async def dedupe(" in content, "Should have dedupe method"
        
        # Should not be building configurations internally
        forbidden_patterns = [
            r"mappings\s*=\s*\[",  # Building mappings array
            r"threshold\s*=\s*\d+", # Setting default threshold
            r"algorithm\s*=\s*['\"]", # Setting default algorithm
        ]
        
        violations = []
        for pattern in forbidden_patterns:
            if re.search(pattern, content):
                # Check it's not in a function signature or comment
                lines = content.split('\n')
                for line in lines:
                    if re.search(pattern, line) and not line.strip().startswith('#'):
                        # Allow if it's a parameter default
                        if 'def ' not in line and 'async def' not in line:
                            violations.append(pattern)
                            break
        
        assert not violations, f"engine_client building configs internally: {violations}"


def test_api_js_passes_config_unchanged():
    """Ensure api.js passes configuration without modification"""
    api_js_file = Path(__file__).parent.parent / "frontend/matching_app/src/services/api.js"
    
    if api_js_file.exists():
        content = api_js_file.read_text()
        
        # Check executeJobV2 function
        assert "executeJobV2" in content, "Should have executeJobV2 function"
        
        # Should have comment about not modifying configuration
        assert "DO NOT modify configuration" in content or "Pass configuration as-is" in content, \
            "Should have comment about not modifying configuration"
        
        # Should not be modifying the configuration
        forbidden_patterns = [
            r"configuration\.\w+\s*=",  # configuration.field = 
            r"configuration\[.*\]\s*=",  # configuration[field] = 
            r"\.\.\.configuration.*threshold", # Spreading and adding threshold
        ]
        
        violations = []
        for pattern in forbidden_patterns:
            if re.search(pattern, content):
                violations.append(pattern)
        
        assert not violations, f"api.js modifying configuration: {violations}"


def test_no_hardcoded_thresholds():
    """Ensure no hardcoded thresholds in services"""
    services_dir = Path(__file__).parent.parent / "src/fmatch/saas/services"
    api_dir = Path(__file__).parent.parent / "src/fmatch/saas/api/v2"
    
    violations = []
    
    for directory in [services_dir, api_dir]:
        for py_file in directory.rglob("*.py"):
            if py_file.suffix != '.py':
                continue
            
            # Skip test files and intelligence.py (allowed to have defaults)
            if 'test' in py_file.name or py_file.name == 'intelligence.py':
                continue
            
            content = py_file.read_text()
            
            # Look for hardcoded thresholds
            pattern = r"threshold\s*=\s*\d+"
            matches = re.findall(pattern, content)
            
            # Filter out parameter defaults in function signatures
            for match in matches:
                lines = content.split('\n')
                for i, line in enumerate(lines):
                    if match in line:
                        # Check if it's in a function signature
                        if 'def ' not in line and 'async def' not in line:
                            # Also check the previous line for multi-line signatures
                            if i > 0 and 'def ' not in lines[i-1] and 'async def' not in lines[i-1]:
                                violations.append(f"{py_file.name}: {match}")
    
    assert not violations, f"Hardcoded thresholds found: {violations}"


def test_quickmatch_simplified():
    """Ensure QuickMatchMain.jsx is simplified (less than 500 lines)"""
    quickmatch_file = Path(__file__).parent.parent / "frontend/matching_app/src/pages/QuickMatch/QuickMatchMain.jsx"
    
    if quickmatch_file.exists():
        content = quickmatch_file.read_text()
        lines = content.split('\n')
        line_count = len(lines)
        
        assert line_count < 500, f"QuickMatchMain.jsx should be simplified. Current: {line_count} lines, Target: < 500 lines"
        
        # Check for removed components
        removed_components = [
            "MappingTable",
            "ConfigurationReview",
            "handleAddMapping",
            "handleRemoveMapping",
            "handleAutoMatch",
            "renderEnhancedFieldMappings",
            "renderFlowSelector",
            "useIntelligentFlow"
        ]
        
        for component in removed_components:
            assert component not in content, f"QuickMatchMain.jsx should not contain {component}"


if __name__ == "__main__":
    # Run tests
    print("Running Architecture Compliance Tests...")
    
    test_no_rapidfuzz_in_services()
    print("✓ No rapidfuzz in services")
    
    test_services_extend_base_intelligent()
    print("✓ Services extend BaseIntelligentService")
    
    test_frontend_no_local_configs()
    print("✓ Frontend doesn't build configs locally")
    
    test_correlation_id_in_intelligence_responses()
    print("✓ Intelligence API returns correlation_id")
    
    test_jobs_validates_correlation_id()
    print("✓ Jobs API validates correlation_id")
    
    test_engine_client_accepts_configs()
    print("✓ Engine client accepts configs directly")
    
    test_api_js_passes_config_unchanged()
    print("✓ api.js passes configuration unchanged")
    
    test_no_hardcoded_thresholds()
    print("✓ No hardcoded thresholds in services")
    
    test_quickmatch_simplified()
    print("✓ QuickMatchMain.jsx is simplified")
    
    print("\n✅ All architecture compliance tests passed!")