"""
Integration tests for error handler middleware

Tests the error handler middleware integration with FastAPI.
"""
import pytest
from fastapi import FastAPI, Request
from fastapi.testclient import TestClient
from src.middlewares.error_handler import setup_error_handler
from src.utils.errors import (
    ProjectNotFoundException,
    TaskTimeoutException,
    InvalidParameterException,
    ModelNotFoundException,
    RateLimitExceededException
)


@pytest.fixture
def app():
    """Create a test FastAPI app with error handler"""
    app = FastAPI()
    
    # Setup error handler
    setup_error_handler(app)
    
    # Test routes that raise different exceptions
    @app.get("/test/business-error")
    async def business_error():
        raise ProjectNotFoundException(project_id="test_123")
    
    @app.get("/test/system-error")
    async def system_error():
        raise TaskTimeoutException(task_id="task_123", timeout=300)
    
    @app.get("/test/invalid-param")
    async def invalid_param():
        raise InvalidParameterException(field="email", reason="Invalid format")
    
    @app.get("/test/model-not-found")
    async def model_not_found():
        raise ModelNotFoundException(model_id="flux-pro")
    
    @app.get("/test/rate-limit")
    async def rate_limit():
        raise RateLimitExceededException(limit=100, window=60)
    
    @app.get("/test/unexpected-error")
    async def unexpected_error():
        raise ValueError("Unexpected error")
    
    @app.get("/test/success")
    async def success():
        return {"message": "Success"}
    
    return app


@pytest.fixture
def client(app):
    """Create a test client"""
    return TestClient(app)


class TestErrorHandlerMiddleware:
    """Test error handler middleware integration"""
    
    def test_business_exception_response(self, client):
        """Test business exception returns 400 with correct format"""
        response = client.get("/test/business-error")
        
        assert response.status_code == 400
        data = response.json()
        
        # Check response format
        assert "code" in data
        assert "message" in data
        assert "details" in data
        assert "request_id" in data
        assert "timestamp" in data
        
        # Check error details
        assert data["code"] == "2001"
        assert "Project not found" in data["message"]
        assert data["details"]["project_id"] == "test_123"
        
        # Check headers
        assert "X-Request-ID" in response.headers
        assert "X-Timestamp" in response.headers
    
    def test_system_exception_response(self, client):
        """Test system exception returns 500 with correct format"""
        response = client.get("/test/system-error")
        
        assert response.status_code == 500
        data = response.json()
        
        assert data["code"] == "3003"
        assert "timeout" in data["message"].lower()
        assert data["details"]["task_id"] == "task_123"
        assert data["details"]["timeout_seconds"] == 300
    
    def test_invalid_parameter_exception(self, client):
        """Test invalid parameter exception"""
        response = client.get("/test/invalid-param")
        
        assert response.status_code == 400
        data = response.json()
        
        assert data["code"] == "1001"
        assert data["details"]["field"] == "email"
        assert data["details"]["reason"] == "Invalid format"
    
    def test_model_not_found_exception(self, client):
        """Test model not found exception"""
        response = client.get("/test/model-not-found")
        
        assert response.status_code == 400
        data = response.json()
        
        assert data["code"] == "4001"
        assert data["details"]["model_id"] == "flux-pro"
    
    def test_rate_limit_exception(self, client):
        """Test rate limit exception returns 429"""
        response = client.get("/test/rate-limit")
        
        assert response.status_code == 429
        data = response.json()
        
        assert data["code"] == "1007"
        assert data["details"]["limit"] == 100
        assert data["details"]["window_seconds"] == 60
    
    def test_unexpected_exception_response(self, client):
        """Test unexpected exception returns 500"""
        response = client.get("/test/unexpected-error")
        
        assert response.status_code == 500
        data = response.json()
        
        assert data["code"] == "1000"
        assert "internal error" in data["message"].lower()
        assert "request_id" in data
        assert "timestamp" in data
    
    def test_success_response_has_headers(self, client):
        """Test successful response includes request ID and timestamp headers"""
        response = client.get("/test/success")
        
        assert response.status_code == 200
        assert "X-Request-ID" in response.headers
        assert "X-Timestamp" in response.headers
    
    def test_request_id_consistency(self, client):
        """Test request ID is consistent in response and headers"""
        response = client.get("/test/business-error")
        
        data = response.json()
        assert data["request_id"] == response.headers["X-Request-ID"]
    
    def test_timestamp_format(self, client):
        """Test timestamp is in ISO format"""
        response = client.get("/test/business-error")
        
        data = response.json()
        timestamp = data["timestamp"]
        
        # Check ISO format (ends with Z for UTC)
        assert timestamp.endswith("Z")
        assert "T" in timestamp
        
        # Verify it's a valid ISO timestamp
        from datetime import datetime
        datetime.fromisoformat(timestamp.replace("Z", "+00:00"))


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
