"""
Endpoints del Módulo B con caching
"""
import logging
from typing import Optional

from fastapi import APIRouter, HTTPException, WebSocket, WebSocketDisconnect, Depends
from pydantic import BaseModel

from app.data.repositories.ruta_repository import SupabaseRutaRepository
from app.services.simulador import obtener_simulador
from app.services.ws_manager import ws_manager
from app.core.cache import cached, cache_client, invalidate_route_cache
from app.core.dependencies import get_current_user
from app.db.database import get_db

router = APIRouter()
logger = logging.getLogger(__name__)


def _repo() -> SupabaseRutaRepository:
    return SupabaseRutaRepository()


# ── GET /eta/{address_id} con caché ─────────────────────────────────────────

@router.get("/eta/{address_id}", summary="Ventana ETA para un domicilio")
@cached(prefix="eta", ttl=30)
async def get_eta(
    address_id: int,
    current_user: dict = Depends(get_current_user)
):
    """
    Devuelve ETA + ventana horaria solo para el domicilio solicitado.
    Cacheado por 30 segundos para evitar consultas repetidas.
    """
    # Verificar que el domicilio pertenece al usuario (RBAC)
    db = get_db()
    try:
        result = db.table("addresses").select("user_id").eq("id", address_id).execute()
        if not result.data or result.data[0]["user_id"] != current_user["id"]:
            raise HTTPException(status_code=403, detail="No autorizado")
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
    
    resultado = _repo().calcular_eta(address_id)
    if not resultado:
        raise HTTPException(status_code=404, detail="Domicilio no encontrado")
    
    return {
        "address_id": resultado.address_id,
        "route_id": resultado.route_id,
        "status": resultado.status,
        "eta_minutos": resultado.eta_minutos,
        "ventana": {
            "inicio": resultado.ventana_inicio,
            "fin": resultado.ventana_fin,
        },
        "mensaje": resultado.mensaje,
        "cached": False,
    }


# ── WS /ws/{address_id} ───────────────────────────────────────────────

@router.websocket("/ws/{address_id}")
async def websocket_address(websocket: WebSocket, address_id: int):
    """WebSocket para recibir notificaciones en tiempo real"""
    zona_key = str(address_id)
    await ws_manager.conectar(websocket, zona_key)
    logger.info(f"[WS] Cliente conectado — address_id={address_id}")
    try:
        while True:
            await websocket.receive_text()  # mantener vivo
    except WebSocketDisconnect:
        ws_manager.desconectar(websocket, zona_key)
        logger.info(f"[WS] Cliente desconectado — address_id={address_id}")


# ── POST /alerts/breakdown ────────────────────────────────────────────

class BreakdownPayload(BaseModel):
    route_id: str
    mensaje: Optional[str] = "El camión reportó una falla mecánica."


@router.post("/alerts/breakdown", summary="Reportar avería de camión")
async def reportar_averia(payload: BreakdownPayload):
    """Endpoint para reportar avería - invalida caché automáticamente"""
    sim = obtener_simulador(payload.route_id)
    await sim.forzar_averia(payload.mensaje)
    
    # Invalidar caché de esta ruta
    await invalidate_route_cache(payload.route_id)
    
    return {
        "ok": True,
        "route_id": payload.route_id,
        "mensaje": "Avería registrada y usuarios notificados",
    }


# ── Admin / Demo ──────────────────────────────────────────────────────

@router.post("/admin/route/{route_id}/start", summary="Iniciar simulación")
async def iniciar_ruta(route_id: str):
    """Iniciar el simulador de camión"""
    obtener_simulador(route_id).iniciar()
    await invalidate_route_cache(route_id)
    return {"ok": True, "mensaje": f"Simulador {route_id} iniciado"}


@router.post("/admin/route/{route_id}/delay", summary="Forzar retraso")
async def forzar_retraso(route_id: str, mensaje: str = "El camión reportó un retraso."):
    """Forzar retraso en la ruta"""
    await obtener_simulador(route_id).forzar_retraso(mensaje)
    await invalidate_route_cache(route_id)
    return {"ok": True, "mensaje": "Retraso notificado"}


@router.get("/admin/route/{route_id}/status", summary="Estado interno del camión")
async def estado_ruta(route_id: str):
    """Obtener estado actual del camión"""
    repo = _repo()
    ts = repo.obtener_truck_status(route_id)
    if not ts:
        raise HTTPException(status_code=404, detail="Ruta no encontrada")
    return {
        "route_id": ts.route_id,
        "current_position_id": ts.current_position_id,
        "status": ts.status.value,
        "last_update": ts.last_update.isoformat(),
        "ws_clientes_activos": ws_manager.zonas_activas(),
    }


# ── Endpoint para limpiar caché (admin) ──────────────────────────────

@router.post("/admin/cache/clear", summary="Limpiar toda la caché")
async def clear_cache():
    """Limpiar caché de Redis y memoria"""
    await cache_client.clear_all()
    return {"ok": True, "mensaje": "Caché limpiada"}


@router.get("/admin/cache/stats", summary="Estadísticas de caché")
async def cache_stats():
    """Estadísticas del sistema de caché"""
    return {
        "enabled": cache_client.enabled,
        "redis_available": cache_client.redis_client is not None,
        "memory_cache_size": len(cache_client.memory_cache),
    }