"""
API Service
===========

FastAPI service for serving sentiment analysis predictions.
"""

import logging
from pathlib import Path
from typing import List, Optional
from pydantic import BaseModel, Field
from fastapi import FastAPI, HTTPException, status
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse

from .model_server import ModelServer

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

# Initialize FastAPI app
app = FastAPI(
    title="Sentiment140 API",
    description="Sentiment analysis API for Twitter data using Sentiment140 model",
    version="1.0.0",
    docs_url="/docs",
    redoc_url="/redoc"
)

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

# Global model server instance
model_server: Optional[ModelServer] = None


# Pydantic models for request/response
class TextInput(BaseModel):
    """Single text input for prediction."""
    text: str = Field(..., min_length=1, max_length=5000, description="Text to analyze")


class BatchTextInput(BaseModel):
    """Batch text input for predictions."""
    texts: List[str] = Field(..., min_items=1, max_items=100, description="List of texts to analyze")


class PredictionResponse(BaseModel):
    """Prediction response model."""
    text: str
    prediction: int
    sentiment: str
    confidence: Optional[float] = None


class BatchPredictionResponse(BaseModel):
    """Batch prediction response model."""
    predictions: List[PredictionResponse]
    count: int


class HealthResponse(BaseModel):
    """Health check response model."""
    status: str
    model_loaded: bool
    version: str


@app.on_event("startup")
async def startup_event():
    """Load model on startup."""
    global model_server
    
    logger.info("Starting up API service...")
    
    # Model paths
    model_path = Path("artifacts_sentiment140/tfidf_svm_sentiment140.joblib")
    label_map_path = Path("artifacts_sentiment140/label_map.json")
    
    try:
        model_server = ModelServer(model_path, label_map_path)
        model_server.load_model()
        logger.info("Model loaded successfully")
    except Exception as e:
        logger.error(f"Failed to load model: {e}")
        logger.warning("API will start but predictions will fail")


@app.on_event("shutdown")
async def shutdown_event():
    """Cleanup on shutdown."""
    logger.info("Shutting down API service...")


@app.get("/", tags=["General"])
async def root():
    """Root endpoint."""
    return {
        "message": "Sentiment140 API",
        "version": "1.0.0",
        "docs": "/docs"
    }


@app.get("/health", response_model=HealthResponse, tags=["General"])
async def health_check():
    """
    Health check endpoint.
    
    Returns:
        Health status of the service
    """
    if model_server is None:
        return HealthResponse(
            status="unhealthy",
            model_loaded=False,
            version="1.0.0"
        )
    
    health_status = model_server.health_check()
    
    return HealthResponse(
        status=health_status["status"],
        model_loaded=health_status["model_loaded"],
        version="1.0.0"
    )


@app.post("/predict", response_model=PredictionResponse, tags=["Prediction"])
async def predict_sentiment(input_data: TextInput):
    """
    Predict sentiment for a single text.
    
    Args:
        input_data: Text input
        
    Returns:
        Prediction result
    """
    if model_server is None or model_server.model is None:
        raise HTTPException(
            status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
            detail="Model not loaded"
        )
    
    try:
        result = model_server.predict_single(input_data.text)
        return PredictionResponse(**result)
    except Exception as e:
        logger.error(f"Prediction error: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Prediction failed: {str(e)}"
        )


@app.post("/predict/batch", response_model=BatchPredictionResponse, tags=["Prediction"])
async def predict_batch(input_data: BatchTextInput):
    """
    Predict sentiment for multiple texts.
    
    Args:
        input_data: Batch text input
        
    Returns:
        Batch prediction results
    """
    if model_server is None or model_server.model is None:
        raise HTTPException(
            status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
            detail="Model not loaded"
        )
    
    try:
        results = model_server.predict(input_data.texts)
        predictions = [PredictionResponse(**r) for r in results]
        
        return BatchPredictionResponse(
            predictions=predictions,
            count=len(predictions)
        )
    except Exception as e:
        logger.error(f"Batch prediction error: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Batch prediction failed: {str(e)}"
        )


@app.get("/model/info", tags=["Model"])
async def get_model_info():
    """
    Get information about the loaded model.
    
    Returns:
        Model information
    """
    if model_server is None:
        raise HTTPException(
            status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
            detail="Model not loaded"
        )
    
    return model_server.get_model_info()


if __name__ == "__main__":
    import uvicorn
    
    uvicorn.run(
        "api_service:app",
        host="0.0.0.0",
        port=8000,
        reload=True,
        log_level="info"
    )
