"""Endpoints del POS: venta, cortesia, anulacion y paquetes."""
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session as DBSession
from database import get_db
from models import Package
from schemas import (
    PackageOut, SellRequest, SellResponse, RetryRequest,
    CortesiaRequest, AnulacionRequest, ReprogramRequest, SupervisorActionResponse,
)
from services.wristband_service import sell_and_program, retry_program, cortesia_and_program, anular_sesion, reprogram_and_program
from services.supervisor_service import validar_pin_supervisor
from rate_limiter import check_sell_rate, MAX_SELLS_PER_MINUTE

router = APIRouter(prefix="/api", tags=["POS"])


@router.get("/packages", response_model=list[PackageOut])
def list_packages(db: DBSession = Depends(get_db)):
    """Lista paquetes activos para mostrar en el POS."""
    return db.query(Package).filter(Package.active == True).all()


@router.post("/sell", response_model=SellResponse)
async def sell(req: SellRequest, db: DBSession = Depends(get_db)):
    """Crea una venta y programa la pulsera."""
    if not check_sell_rate(req.agent_id):
        raise HTTPException(
            status_code=429,
            detail=f"Rate limit: maximo {MAX_SELLS_PER_MINUTE} ventas/minuto por agente",
        )

    result = await sell_and_program(
        db=db,
        package_id=req.package_id,
        payment_method=req.payment_method,
        amount=req.amount_received,
        cashier=req.cashier,
        agent_id=req.agent_id,
        timeout=req.timeout,
        red_minutes=req.red_minutes,
        green_minutes=req.green_minutes,
        blue_minutes=req.blue_minutes,
    )

    # Errores de validacion tempranos (no tienen session_id aun)
    if result.get('status') == 'error' and 'session_id' not in result:
        raise HTTPException(status_code=400, detail=result.get('message', 'Error desconocido'))

    return SellResponse(**result)


@router.post("/sell/{session_id}/retry", response_model=SellResponse)
async def retry(session_id: str, req: RetryRequest = RetryRequest(), db: DBSession = Depends(get_db)):
    """Reintenta programar una venta fallida."""
    result = await retry_program(db, session_id, timeout=req.timeout)
    return SellResponse(**result)


@router.post("/cortesia", response_model=SupervisorActionResponse)
async def cortesia(req: CortesiaRequest, db: DBSession = Depends(get_db)):
    """Cortesia: pulsera gratis con aprobacion de supervisor."""
    if not req.motivo or not req.motivo.strip():
        raise HTTPException(status_code=400, detail="Motivo/justificacion es obligatorio")

    # 1. Validar PIN contra cloud (si se proporciona)
    supervisor_name = req.supervisor
    if req.pin_supervisor:
        try:
            pin_result = await validar_pin_supervisor(req.pin_supervisor, 'cortesia', req.cashier, req.motivo)
        except Exception:
            raise HTTPException(status_code=503, detail="No se pudo conectar al servidor cloud para validar PIN")
        if pin_result.get('status') != 'ok':
            raise HTTPException(status_code=403, detail=pin_result.get('message', 'PIN de supervisor invalido'))
        supervisor_name = pin_result['supervisor']
    elif not supervisor_name:
        raise HTTPException(status_code=400, detail="Se requiere PIN de supervisor o nombre de supervisor pre-validado")

    # 2. Rate limit (misma logica que /sell)
    if not check_sell_rate(req.agent_id):
        raise HTTPException(
            status_code=429,
            detail=f"Rate limit: maximo {MAX_SELLS_PER_MINUTE} ventas/minuto por agente",
        )

    # 3. Programar cortesia
    result = await cortesia_and_program(
        db=db,
        package_id=req.package_id,
        cashier=req.cashier,
        supervisor=supervisor_name,
        motivo=req.motivo,
        agent_id=req.agent_id,
        timeout=req.timeout,
        red_minutes=req.red_minutes,
        green_minutes=req.green_minutes,
        blue_minutes=req.blue_minutes,
    )
    return SupervisorActionResponse(**result)


@router.post("/sell/{session_id}/anular", response_model=SupervisorActionResponse)
async def anular(session_id: str, req: AnulacionRequest, db: DBSession = Depends(get_db)):
    """Anula una venta activa con aprobacion de supervisor."""
    if not req.motivo or not req.motivo.strip():
        raise HTTPException(status_code=400, detail="Motivo/justificacion es obligatorio")

    # 1. Validar PIN contra cloud (si se proporciona)
    supervisor_name = req.supervisor
    if req.pin_supervisor:
        try:
            pin_result = await validar_pin_supervisor(req.pin_supervisor, 'anulacion', req.cashier, req.motivo)
        except Exception:
            raise HTTPException(status_code=503, detail="No se pudo conectar al servidor cloud para validar PIN")
        if pin_result.get('status') != 'ok':
            raise HTTPException(status_code=403, detail=pin_result.get('message', 'PIN de supervisor invalido'))
        supervisor_name = pin_result['supervisor']
    elif not supervisor_name:
        raise HTTPException(status_code=400, detail="Se requiere PIN de supervisor o nombre de supervisor pre-validado")

    # 2. Anular sesion
    result = anular_sesion(
        db=db,
        session_id=session_id,
        cashier=req.cashier,
        supervisor=supervisor_name,
        motivo=req.motivo,
    )

    if result['status'] == 'error':
        raise HTTPException(status_code=400, detail=result['message'])

    return SupervisorActionResponse(**result)


@router.post("/sell/{session_id}/reprogram", response_model=SupervisorActionResponse)
async def reprogram(session_id: str, req: ReprogramRequest, db: DBSession = Depends(get_db)):
    """Reprograma una pulsera activa con un paquete diferente (requiere supervisor)."""
    if not req.motivo or not req.motivo.strip():
        raise HTTPException(status_code=400, detail="Motivo/justificacion es obligatorio")

    # 1. Validar PIN contra cloud (si se proporciona)
    supervisor_name = req.supervisor
    if req.pin_supervisor:
        try:
            pin_result = await validar_pin_supervisor(req.pin_supervisor, 'reprogram', req.cashier, req.motivo)
        except Exception:
            raise HTTPException(status_code=503, detail="No se pudo conectar al servidor cloud para validar PIN")
        if pin_result.get('status') != 'ok':
            raise HTTPException(status_code=403, detail=pin_result.get('message', 'PIN de supervisor invalido'))
        supervisor_name = pin_result['supervisor']
    elif not supervisor_name:
        raise HTTPException(status_code=400, detail="Se requiere PIN de supervisor o nombre de supervisor pre-validado")

    # 2. Rate limit
    if not check_sell_rate(req.agent_id):
        raise HTTPException(
            status_code=429,
            detail=f"Rate limit: maximo {MAX_SELLS_PER_MINUTE} ventas/minuto por agente",
        )

    # 3. Reprogramar
    result = await reprogram_and_program(
        db=db,
        session_id=session_id,
        package_id=req.package_id,
        cashier=req.cashier,
        supervisor=supervisor_name,
        motivo=req.motivo,
        agent_id=req.agent_id,
        timeout=req.timeout,
    )

    if result['status'] == 'error':
        raise HTTPException(status_code=400, detail=result['message'])

    return SupervisorActionResponse(**result)
