"""
Production-Ready Facebook Auto Reply Bot Engine
Enterprise-grade architecture with proper separation of concerns
"""
from fastapi import FastAPI, Request, HTTPException, BackgroundTasks, Header
from fastapi.responses import JSONResponse
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.gzip import GZipMiddleware
from contextlib import asynccontextmanager
from typing import Optional
import time

from config import get_settings
from app.core.logging import setup_logging, get_logger
from app.core.security import WebhookValidator
from app.services.rate_limiter import RateLimiter
from app.services.deduplicator import MessageDeduplicator
from app.services.redis_rate_limiter import RedisRateLimiter
from app.services.redis_deduplicator import RedisMessageDeduplicator
from app.services.circuit_breaker import CircuitBreaker
from app.services.metrics import MetricsCollector
from app.clients.laravel_client import LaravelAPIClient
from app.clients.facebook_client import FacebookAPIClient
from app.api.models import WebhookData
from app.processors.message_processor import MessageProcessor
import redis.asyncio as redis

# Initialize configuration and logging
settings = get_settings()
setup_logging()
logger = get_logger(__name__)

# Global components
rate_limiter: RateLimiter
deduplicator: MessageDeduplicator
circuit_breaker: CircuitBreaker
metrics: MetricsCollector
laravel_client: LaravelAPIClient
facebook_client: FacebookAPIClient
message_processor: MessageProcessor
webhook_validator: WebhookValidator
redis_client: Optional[redis.Redis] = None


@asynccontextmanager
async def lifespan(app: FastAPI):
    """Application lifespan management"""
    global rate_limiter, deduplicator, circuit_breaker, metrics
    global laravel_client, facebook_client, message_processor, webhook_validator, redis_client
    
    # Startup
    logger.info(f"Starting {settings.app_name} v2.0.0")
    logger.info(f"Environment: {settings.environment}")
    
    # Try to connect to Redis
    try:
        redis_url = f"redis://{settings.redis_host}:{settings.redis_port}/{settings.redis_db}"
        if settings.redis_password:
            redis_url = f"redis://:{settings.redis_password}@{settings.redis_host}:{settings.redis_port}/{settings.redis_db}"
        
        redis_client = redis.from_url(redis_url, decode_responses=True)
        await redis_client.ping()
        logger.info("✓ Redis connected successfully")
        
        # Use Redis-backed services
        rate_limiter = RedisRateLimiter(
            redis_client,
            max_requests=settings.rate_limit_max_requests,
            time_window=settings.rate_limit_time_window
        )
        deduplicator = RedisMessageDeduplicator(
            redis_client,
            ttl=settings.message_deduplication_ttl
        )
        logger.info("✓ Using Redis for rate limiting and deduplication")
        
    except Exception as e:
        logger.warning(f"Redis connection failed: {e}")
        logger.info("✓ Falling back to in-memory services")
        redis_client = None
        
        # Use in-memory services as fallback
        rate_limiter = RateLimiter(
            max_requests=settings.rate_limit_max_requests,
            time_window=settings.rate_limit_time_window
        )
        deduplicator = MessageDeduplicator(ttl=settings.message_deduplication_ttl)
    
    # Initialize other components
    circuit_breaker = CircuitBreaker(
        failure_threshold=settings.circuit_breaker_failure_threshold,
        timeout=settings.circuit_breaker_timeout
    )
    metrics = MetricsCollector()
    webhook_validator = WebhookValidator()
    
    # Initialize clients
    laravel_client = LaravelAPIClient(circuit_breaker)
    await laravel_client.initialize()
    
    facebook_client = FacebookAPIClient()
    message_processor = MessageProcessor(laravel_client, facebook_client)
    
    logger.info("All components initialized successfully")
    
    yield
    
    # Shutdown
    logger.info("Shutting down application...")
    await laravel_client.close()
    if redis_client:
        await redis_client.close()
        logger.info("Redis connection closed")
    logger.info("Application stopped")


# Initialize FastAPI
app = FastAPI(
    title=settings.app_name,
    description="Enterprise-grade Facebook Auto Reply Bot Engine",
    version="2.0.0",
    lifespan=lifespan
)

# Middleware
app.add_middleware(GZipMiddleware, minimum_size=1000)
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


@app.get("/webhook")
async def verify_webhook(request: Request):
    """Facebook webhook verification"""
    mode = request.query_params.get("hub.mode")
    token = request.query_params.get("hub.verify_token")
    challenge = request.query_params.get("hub.challenge")
    
    if mode == "subscribe" and token == settings.facebook_verify_token:
        logger.info("Webhook verified successfully")
        return JSONResponse(content=int(challenge))
    
    logger.warning("Webhook verification failed")
    raise HTTPException(status_code=403, detail="Verification failed")


@app.post("/webhook")
async def handle_webhook(
    request: Request,
    webhook_data: WebhookData,
    background_tasks: BackgroundTasks,
    x_hub_signature_256: Optional[str] = Header(None)
):
    """Main webhook endpoint"""
    
    # Validate signature in production
    if settings.environment == "production":
        body = await request.body()
        if not webhook_validator.validate_signature(
            body,
            x_hub_signature_256,
            settings.facebook_app_secret
        ):
            logger.warning("Invalid webhook signature")
            raise HTTPException(status_code=403, detail="Invalid signature")
    
    if webhook_data.object != "page":
        raise HTTPException(status_code=400, detail="Invalid object type")
    
    # Process messages in background
    for entry in webhook_data.entry:
        if entry.messaging:
            for messaging_event in entry.messaging:
                background_tasks.add_task(
                    process_messaging_event,
                    entry.id,
                    messaging_event
                )
    
    return JSONResponse(content={"status": "ok"})


async def process_messaging_event(page_id: str, event: dict):
    """Process individual messaging event"""
    start_time = time.time()
    
    try:
        await message_processor.process(page_id, event, metrics, rate_limiter, deduplicator)
        
        # Record processing time
        processing_time = (time.time() - start_time) * 1000
        metrics.record_processing_time(processing_time)
        logger.info(f"Message processed in {processing_time:.2f}ms")
        
    except Exception as e:
        logger.error(f"Error processing event: {e}", exc_info=True)
        metrics.increment("errors")


@app.get("/health")
async def health_check():
    """Health check endpoint"""
    redis_status = "disconnected"
    if redis_client:
        try:
            await redis_client.ping()
            redis_status = "connected"
        except:
            redis_status = "error"
    
    return {
        "status": "healthy",
        "service": settings.app_name,
        "version": "2.0.0",
        "environment": settings.environment,
        "circuit_breaker_state": circuit_breaker.state,
        "redis_status": redis_status
    }


@app.get("/metrics")
async def get_metrics():
    """Metrics endpoint"""
    return metrics.get_metrics()


@app.get("/")
async def root():
    """Root endpoint"""
    return {
        "service": settings.app_name,
        "version": "2.0.0",
        "status": "running"
    }


if __name__ == "__main__":
    import uvicorn
    uvicorn.run(
        "app.main:app",
        host="0.0.0.0",
        port=8000,
        reload=settings.debug,
        log_level=settings.log_level.lower()
    )
