"""FastAPI application with fast multi-threaded Selenium scrapers."""

import logging
import os
from contextlib import asynccontextmanager
from fastapi import FastAPI, HTTPException, Query
from fastapi.responses import JSONResponse
from fastapi.middleware.cors import CORSMiddleware
from typing import Optional, List
import asyncio
import time

from src.models.schemas import (
    ScrapeRequest, HealthResponse
)
from src.services.database import db_service
from src.services.cache_service import cache_service
from src.services.monitoring_service import monitoring_service
from src.scrapers.multi_engine_manager import multi_engine_manager
from src.config.settings import LOG_LEVEL, LOG_FORMAT

# Configure logging
logging.basicConfig(level=getattr(logging, LOG_LEVEL), format=LOG_FORMAT)
logger = logging.getLogger(__name__)

@asynccontextmanager
async def lifespan(app: FastAPI):
    """Application lifespan manager with fast startup."""
    # Startup
    logger.info("Starting up the fast Selenium application...")
    
    # Initialize database
    try:
        await db_service.connect()
        logger.info("Database connected")
    except Exception as e:
        logger.warning(f"Database connection failed: {e}")
    
    # Initialize cache
    try:
        cache_service.connect()
        logger.info("Cache connected")
    except Exception as e:
        logger.warning(f"Cache connection failed: {e}")
    
    # Skip engine performance test during startup for faster initialization
    # Test can be run manually via /performance/test endpoint
    skip_startup_test = os.getenv("SKIP_STARTUP_TEST", "true").lower() == "true"
    
    if not skip_startup_test:
        try:
            performance_results = multi_engine_manager.test_engine_performance()
            logger.info(f"Engine performance test completed: {len(performance_results)} engines tested")
        except Exception as e:
            logger.warning(f"Engine performance test failed: {e}")
    else:
        logger.info("Skipping startup engine test for faster initialization")
    
    logger.info("Fast Selenium application started successfully")
    
    yield
    
    # Shutdown
    logger.info("Shutting down the application...")
    
    # Close connections
    try:
        await db_service.disconnect()
    except:
        pass
    
    try:
        cache_service.disconnect()
    except:
        pass
    
    try:
        multi_engine_manager.close()
    except:
        pass
    
    logger.info("Application shut down successfully")

app = FastAPI(
    title="Fast Multi-Threaded Selenium Scraper API",
    description="High-performance multi-engine search scraper with fast Selenium and parallel processing",
    version="3.0.0",
    lifespan=lifespan
)

# Add CORS middleware
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.get("/")
async def root():
    """Root endpoint."""
    return {
        "message": "Fast Multi-Threaded Selenium Scraper API",
        "version": "3.0.0",
        "status": "ready",
        "features": [
            "Multi-threaded Selenium scraping",
            "Ultra-fast optimized Chrome drivers",
            "Parallel engine processing",
            "Performance monitoring",
            "Redis caching",
            "Real-time statistics"
        ],
        "engines": multi_engine_manager.get_available_engines()
    }

@app.get("/health")
async def health_check():
    """Enhanced health check endpoint."""
    services = {
        "selenium_manager": True,
        "database": db_service.client is not None,
        "cache": cache_service.connected if cache_service else False,
    }
    
    status = "healthy" if all(services.values()) else "unhealthy"
    
    return {
        "status": status,
        "services": services,
        "timestamp": time.time()
    }

@app.get("/engines")
async def get_engines():
    """Get available search engines."""
    return {
        "available_engines": multi_engine_manager.get_available_engines(),
        "descriptions": multi_engine_manager.get_engine_descriptions()
    }

@app.post("/scrape/fast")
async def scrape_fast(request: ScrapeRequest):
    """Fast parallel scraping endpoint."""
    start_time = time.time()
    
    try:
        # Validate engines
        available_engines = multi_engine_manager.get_available_engines()
        if "all" not in request.engines:
            invalid_engines = [e for e in request.engines if e not in available_engines]
            if invalid_engines:
                raise HTTPException(
                    status_code=400,
                    detail=f"Invalid engines: {invalid_engines}. Available: {available_engines}"
                )
        
        # Perform parallel scraping
        results = await multi_engine_manager.scrape_multiple_engines_parallel(request)
        
        # Prepare response
        execution_time = time.time() - start_time
        engines_used = multi_engine_manager._resolve_engines(request.engines)
        
        # Group results by engine
        results_by_engine = {}
        for result in results:
            if result.engine not in results_by_engine:
                results_by_engine[result.engine] = []
            results_by_engine[result.engine].append({
                "title": result.title,
                "url": result.url,
                "description": result.description,
                "position": result.position,
                "timestamp": result.timestamp.isoformat()
            })
        
        return JSONResponse(content={
            "query": request.query,
            "engines_used": engines_used,
            "total_results": len(results),
            "execution_time": round(execution_time, 2),
            "results_by_engine": results_by_engine,
            "all_results": [
                {
                    "title": result.title,
                    "url": result.url,
                    "description": result.description,
                    "engine": result.engine,
                    "position": result.position,
                    "timestamp": result.timestamp.isoformat()
                } for result in results
            ]
        })
        
    except Exception as e:
        logger.error(f"Error in fast scraping: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@app.get("/search/direct")
async def direct_search(
    query: str = Query(..., description="Search query"),
    engines: List[str] = Query(["bing"], description="Search engines to use"),
    max_results: int = Query(5, ge=1, le=50, description="Maximum results per engine"),
    parallel: bool = Query(True, description="Use parallel processing")
):
    """Direct search endpoint with parallel/sequential options."""
    try:
        request = ScrapeRequest(
            query=query,
            engines=engines,
            max_results=max_results
        )
        
        start_time = time.time()
        
        if parallel:
            results = await multi_engine_manager.scrape_multiple_engines_parallel(request)
        else:
            results = await multi_engine_manager.scrape_multiple_engines_sequential(request)
        
        execution_time = time.time() - start_time
        
        return JSONResponse(content={
            "query": query,
            "engines": engines,
            "parallel_processing": parallel,
            "execution_time": round(execution_time, 2),
            "total_results": len(results),
            "results": [
                {
                    "title": result.title,
                    "url": result.url,
                    "description": result.description,
                    "engine": result.engine,
                    "position": result.position,
                    "timestamp": result.timestamp.isoformat()
                } for result in results
            ]
        })
        
    except Exception as e:
        logger.error(f"Error in direct search: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@app.get("/performance/stats")
async def get_performance_stats():
    """Get performance statistics."""
    try:
        stats = multi_engine_manager.get_performance_stats()
        return JSONResponse(content=stats)
    except Exception as e:
        logger.error(f"Error getting performance stats: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@app.post("/performance/reset")
async def reset_performance_stats():
    """Reset performance statistics."""
    try:
        multi_engine_manager.reset_stats()
        return JSONResponse(content={"message": "Performance statistics reset"})
    except Exception as e:
        logger.error(f"Error resetting performance stats: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@app.get("/performance/test")
async def test_engine_performance(
    test_query: str = Query("test search", description="Query to test with")
):
    """Test performance of all engines."""
    try:
        results = multi_engine_manager.test_engine_performance(test_query)
        return JSONResponse(content={
            "test_query": test_query,
            "results": results
        })
    except Exception as e:
        logger.error(f"Error testing engine performance: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@app.get("/cache/stats")
async def get_cache_stats():
    """Get cache statistics."""
    try:
        if cache_service:
            stats = cache_service.get_cache_stats()
            return JSONResponse(content=stats)
        else:
            return JSONResponse(content={"enabled": False})
    except Exception as e:
        logger.error(f"Error getting cache stats: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@app.delete("/cache")
async def clear_cache():
    """Clear all cached results."""
    try:
        if cache_service and hasattr(cache_service, 'invalidate_cache'):
            cleared_count = cache_service.invalidate_cache()
            return JSONResponse(content={
                "message": f"Cleared {cleared_count} cached entries",
                "cleared_count": cleared_count
            })
        else:
            return JSONResponse(content={"message": "Cache not enabled"})
    except Exception as e:
        logger.error(f"Error clearing cache: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@app.get("/health/detailed")
async def detailed_health_check():
    """Detailed health check with engine status."""
    try:
        engine_health = multi_engine_manager.get_engine_health()
        
        overall_health = all(engine['healthy'] for engine in engine_health.values())
        
        return JSONResponse(content={
            "status": "healthy" if overall_health else "degraded",
            "engines": engine_health,
            "total_engines": len(engine_health),
            "healthy_engines": sum(1 for e in engine_health.values() if e['healthy']),
            "timestamp": time.time()
        })
    except Exception as e:
        logger.error(f"Error in detailed health check: {e}")
        return JSONResponse(content={
            "status": "unhealthy",
            "error": str(e),
            "timestamp": time.time()
        }, status_code=500)

@app.get("/debug/info")
async def debug_info():
    """Debug information for troubleshooting."""
    try:
        stats = multi_engine_manager.get_performance_stats()
        
        return JSONResponse(content={
            "system_info": {
                "available_engines": multi_engine_manager.get_available_engines(),
                "max_workers": multi_engine_manager.max_workers,
                "headless_mode": multi_engine_manager.headless,
                "cache_enabled": multi_engine_manager.use_cache
            },
            "performance_stats": stats,
            "container_info": {
                "python_version": "3.11",
                "selenium_version": "4.15.2",
                "chrome_available": True
            }
        })
    except Exception as e:
        logger.error(f"Error getting debug info: {e}")
        return JSONResponse(content={"error": str(e)}, status_code=500)

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)
