"""
Contract test for L2A API handling of bad Salesforce IDs
=========================================================
"""
import pytest
import sys
sys.path.insert(0, 'src')

from unittest.mock import Mock, patch, AsyncMock
from fastapi.testclient import TestClient
from sqlalchemy.ext.asyncio import AsyncSession


class TestL2ABadIdContract:
    """Contract test to ensure bad IDs don't cause 500 errors"""
    
    @pytest.fixture
    def mock_db(self):
        """Mock database session"""
        db = AsyncMock(spec=AsyncSession)
        # Mock the policy query
        db.execute.return_value.scalar_one_or_none.return_value = Mock(
            id="test-policy-id",
            account_id="test-account",
            status="ACTIVE"
        )
        db.execute.return_value.all.return_value = [("test-policy-id",)]
        db.execute.return_value.scalar_one.return_value = 0  # total count
        db.execute.return_value.scalars.return_value.all.return_value = []  # suggestions
        return db
    
    @pytest.fixture  
    def mock_sf_client(self):
        """Mock Salesforce client"""
        sf = Mock()
        
        async def mock_soql(query, **kwargs):
            # Assert that test-lead-001 never makes it to SOQL
            assert "test-lead-001" not in query, "Invalid ID should not be in SOQL query"
            return {"records": [], "done": True}
        
        sf.soql = AsyncMock(side_effect=mock_soql)
        return sf
    
    @pytest.fixture
    def client(self, mock_db, mock_sf_client):
        """Create test client with mocks"""
        from src.fmatch.saas.main import app
        
        # Override dependencies
        from src.fmatch.saas.db import get_session
        
        async def override_get_session():
            return mock_db
        
        app.dependency_overrides[get_session] = override_get_session
        
        # Mock Salesforce client creation
        with patch('src.fmatch.saas.api.v2.l2a.SalesforceClient') as mock_sf_class:
            mock_sf_class.return_value = mock_sf_client
            
            client = TestClient(app)
            yield client
        
        # Clean up
        app.dependency_overrides.clear()
    
    def test_l2a_suggestions_ignores_bad_ids(self, client, monkeypatch):
        """Test that bad IDs are filtered and API returns 200"""
        # Set development mode for auth bypass
        monkeypatch.setenv("ENV", "development")
        monkeypatch.setenv("ALLOW_INSECURE_API_KEY_FALLBACK", "true")
        
        # Mock suggestions with bad IDs
        from src.fmatch.saas.model_defs.l2a_models import L2ASuggestion
        
        suggestions = [
            Mock(
                spec=L2ASuggestion,
                id="sug-1",
                lead_id="00Qxx000003DGb1",  # Valid Lead ID
                account_id="001xx000003DGb2",  # Valid Account ID
                score=0.85,
                tier="CERTAIN",
                status="pending",
                reasons={},
                explanation="Test",
                created_at="2024-01-01T00:00:00",
                field_score_details="[]"
            ),
            Mock(
                spec=L2ASuggestion,
                id="sug-2", 
                lead_id="test-lead-001",  # Invalid ID
                account_id="invalid-account",  # Invalid ID
                score=0.75,
                tier="PROBABLE",
                status="pending",
                reasons={},
                explanation="Test",
                created_at="2024-01-01T00:00:00",
                field_score_details="[]"
            )
        ]
        
        # Make the API call
        response = client.get(
            "/api/v2/l2a/suggestions?include=explanations",
            headers={"Authorization": "Bearer dev-token"}
        )
        
        # Should return 200, not 500
        assert response.status_code == 200
        
        # Check response structure
        payload = response.json()
        assert "items" in payload
        assert "total" in payload
        assert payload["total"] >= 0
        
        # If warnings are present, check them
        if "warnings" in payload:
            assert isinstance(payload["warnings"], list)
            # Should mention filtered IDs
            warning_text = " ".join(payload["warnings"])
            assert "filtered" in warning_text.lower() or "invalid" in warning_text.lower()
    
    def test_all_invalid_ids_returns_empty_200(self, client, monkeypatch):
        """Test that all invalid IDs return empty 200 with warning"""
        monkeypatch.setenv("ENV", "development")
        
        # Mock suggestions with only bad IDs
        suggestions = [
            Mock(
                lead_id="test-lead-001",
                account_id="invalid-account",
                score=0.75,
                tier="PROBABLE"
            )
        ]
        
        response = client.get(
            "/api/v2/l2a/suggestions",
            headers={"Authorization": "Bearer dev-token"}
        )
        
        assert response.status_code == 200
        payload = response.json()
        assert payload["items"] == []
        assert payload["total"] == 0
        
        # Should have warning about no valid IDs
        if "warnings" in payload:
            assert any("no valid" in w.lower() for w in payload["warnings"])


def test_id_validation_functions():
    """Test the ID validation helper functions directly"""
    from src.fmatch.saas.api.v2.l2a import (
        _valid_sf_ids,
        _filter_by_prefix,
        sf15_to_18,
        _canonicalize_ids
    )
    
    # Test validation
    assert _valid_sf_ids(["00Qxx000003DGb1", "test-lead-001"]) == ["00Qxx000003DGb1"]
    
    # Test prefix filtering
    lead_ids = ["00Qxx000003DGb1", "001xx000003DGb2"]  # Lead and Account
    filtered = _filter_by_prefix(lead_ids, "Lead")
    assert filtered == ["00Qxx000003DGb1"]  # Only Lead ID kept
    
    # Test 15 to 18 conversion
    id_15 = "00Qxx000003DGb1"
    id_18 = sf15_to_18(id_15)
    assert len(id_18) == 18
    assert id_18.startswith(id_15)
    
    # Test canonicalization
    mixed_ids = ["00Qxx000003DGb1", "001xx000003DGb2AAO"]  # 15 and 18 char
    canonical = _canonicalize_ids(mixed_ids)
    assert len(canonical[0]) == 18  # 15-char converted to 18
    assert canonical[1] == "001xx000003DGb2AAO"  # 18-char unchanged


if __name__ == "__main__":
    # Run direct function tests
    test_id_validation_functions()
    print("✓ ID validation functions work correctly")
    
    # Run pytest for contract tests
    pytest.main([__file__, "-v"])