"""Endpoints para registro de combos custom y asignacion a terminales."""
import json
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session as DBSession
from config import VENUE_ID
from database import get_db
from models import ComboRegistry, TerminalPackage, AuditLog, SyncQueue
from schemas import (
    ComboRegisterRequest, ComboRegistryOut,
    TerminalPackageCreate, TerminalPackageOut,
)

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


# --- Registro de combos ---

@router.post("/combos/register", response_model=ComboRegistryOut, status_code=201)
def register_combo(req: ComboRegisterRequest, agent_id: str = None,
                   db: DBSession = Depends(get_db)):
    """La app registra un combo_id local para que el Operator lo vea."""
    if not req.combo_id.startswith("C-"):
        raise HTTPException(status_code=400, detail="combo_id debe comenzar con 'C-'")

    config_str = json.dumps(req.config, ensure_ascii=False) if req.config else None

    # Idempotente: si ya existe, actualizar config y re-encolar sync
    existing = db.query(ComboRegistry).filter(
        ComboRegistry.combo_id == req.combo_id
    ).first()
    if existing:
        if config_str:
            existing.config_json = config_str
        db.add(SyncQueue(
            table_name='combo_registry',
            record_id=req.combo_id,
            action='insert',
            payload=json.dumps({
                'combo_id': req.combo_id,
                'agent_id': existing.agent_id,
                'venue_id': VENUE_ID,
                'config_json': existing.config_json,
            }),
        ))
        db.commit()
        return existing

    combo = ComboRegistry(
        combo_id=req.combo_id,
        agent_id=agent_id or "unknown",
        venue_id=VENUE_ID,
        config_json=config_str,
    )
    db.add(combo)

    # Cola de sync al cloud
    db.add(SyncQueue(
        table_name='combo_registry',
        record_id=req.combo_id,
        action='insert',
        payload=json.dumps({
            'combo_id': req.combo_id,
            'agent_id': agent_id or "unknown",
            'venue_id': VENUE_ID,
            'config_json': config_str,
        }),
    ))

    db.commit()
    db.refresh(combo)
    return combo


@router.delete("/combos/{combo_id}")
def delete_combo(combo_id: str, db: DBSession = Depends(get_db)):
    """Elimina un combo del registro local y encola sync de eliminacion al cloud."""
    combo = db.query(ComboRegistry).filter(
        ComboRegistry.combo_id == combo_id
    ).first()
    if not combo:
        raise HTTPException(status_code=404, detail="Combo no encontrado")

    # Desactivar terminal_packages asociados
    tps = db.query(TerminalPackage).filter(
        TerminalPackage.combo_id == combo_id,
        TerminalPackage.active == True,
    ).all()
    for tp in tps:
        tp.active = False

    # Encolar sync de eliminacion al cloud
    db.add(SyncQueue(
        table_name='combo_registry',
        record_id=combo_id,
        action='delete',
        payload=json.dumps({
            'combo_id': combo_id,
            'venue_id': VENUE_ID,
        }),
    ))

    db.delete(combo)
    db.commit()
    return {"status": "ok", "message": f"Combo {combo_id} eliminado"}


@router.get("/terminals/{terminal_id}/combos", response_model=list[ComboRegistryOut])
def list_terminal_combos(terminal_id: str, db: DBSession = Depends(get_db)):
    """Lista combos registrados (no asignados) por un terminal."""
    return db.query(ComboRegistry).filter(
        ComboRegistry.agent_id == terminal_id
    ).order_by(ComboRegistry.created_at.desc()).all()


# --- Paquetes asignados a terminales ---

@router.get("/venue/packages", response_model=list[TerminalPackageOut])
def list_venue_packages(db: DBSession = Depends(get_db)):
    """Lista TODOS los combos adoptados del venue (todas las terminales)."""
    return db.query(TerminalPackage).filter(
        TerminalPackage.active == True,
    ).all()


@router.get("/terminals/{terminal_id}/packages", response_model=list[TerminalPackageOut])
def list_terminal_packages(terminal_id: str, db: DBSession = Depends(get_db)):
    """Lista combos asignados (con nombre/precio) para un terminal."""
    return db.query(TerminalPackage).filter(
        TerminalPackage.agent_id == terminal_id,
        TerminalPackage.active == True,
    ).all()


@router.post("/terminals/{terminal_id}/packages", response_model=TerminalPackageOut,
             status_code=201)
def assign_combo_to_terminal(terminal_id: str, req: TerminalPackageCreate,
                             db: DBSession = Depends(get_db)):
    """Asigna un combo a un terminal (o actualiza nombre/precio si ya existe)."""
    # Validar que el combo existe en el registro
    combo = db.query(ComboRegistry).filter(
        ComboRegistry.combo_id == req.combo_id
    ).first()
    if not combo:
        raise HTTPException(
            status_code=404,
            detail=f"Combo '{req.combo_id}' no registrado. La app debe registrarlo primero.",
        )

    # Upsert: buscar existente (incluso inactivo)
    existing = db.query(TerminalPackage).filter(
        TerminalPackage.agent_id == terminal_id,
        TerminalPackage.combo_id == req.combo_id,
    ).first()

    if existing:
        existing.name = req.name
        existing.price = req.price
        existing.active = True
        tp = existing
    else:
        tp = TerminalPackage(
            agent_id=terminal_id,
            combo_id=req.combo_id,
            name=req.name,
            price=req.price,
        )
        db.add(tp)

    db.add(AuditLog(
        action='combo_assigned',
        details=json.dumps({
            'terminal': terminal_id,
            'combo_id': req.combo_id,
            'name': req.name,
            'price': req.price,
        }),
    ))

    # Cola de sync al cloud
    db.add(SyncQueue(
        table_name='terminal_packages',
        record_id=f"{terminal_id}:{req.combo_id}",
        action='combo_assign',
        payload=json.dumps({
            'agent_id': terminal_id,
            'combo_id': req.combo_id,
            'name': req.name,
            'price': req.price,
            'active': True,
        }),
    ))

    db.commit()
    db.refresh(tp)
    return tp


@router.delete("/terminals/{terminal_id}/packages/{combo_id}")
def unassign_combo(terminal_id: str, combo_id: str,
                   db: DBSession = Depends(get_db)):
    """Desvincula un combo de un terminal (soft delete)."""
    tp = db.query(TerminalPackage).filter(
        TerminalPackage.agent_id == terminal_id,
        TerminalPackage.combo_id == combo_id,
        TerminalPackage.active == True,
    ).first()
    if not tp:
        raise HTTPException(status_code=404, detail="Combo no asignado a esta terminal")

    tp.active = False

    db.add(AuditLog(
        action='combo_unassigned',
        details=json.dumps({
            'terminal': terminal_id,
            'combo_id': combo_id,
        }),
    ))

    # Cola de sync al cloud
    db.add(SyncQueue(
        table_name='terminal_packages',
        record_id=f"{terminal_id}:{combo_id}",
        action='combo_unassign',
        payload=json.dumps({
            'agent_id': terminal_id,
            'combo_id': combo_id,
        }),
    ))

    db.commit()
    return {"status": "ok", "message": f"Combo {combo_id} desvinculado de {terminal_id}"}
