"""
ICEBERG Manillas POS - Central Server
======================================
FastAPI server que sirve el POS web y la API REST.

Uso:
  cd server
  uvicorn main:app --host 0.0.0.0 --port 8000
"""
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from fastapi.responses import RedirectResponse
import json
from database import init_db, SessionLocal
from models import Package, Agent, SyncQueue, ComboRegistry
from config import DEFAULT_PACKAGES, VENUE_NAME, SERVER_HOST, SERVER_PORT, REGISTERED_AGENTS, APP_VERSION
from routers import pos, sessions, hardware, agents, sync, health, auth_local, odoo, terminals, supervisor
from discovery import publish_service, unpublish_service
from sync_worker import sync_worker
from cloud_poller import cloud_poller
import os
import asyncio
from datetime import datetime, timedelta

HEARTBEAT_TIMEOUT = 60  # segundos sin heartbeat para marcar offline
HEARTBEAT_CHECK_INTERVAL = 30  # cada cuanto verificar

app = FastAPI(
    title=f"ICEBERG Manillas POS - {VENUE_NAME}",
    version=APP_VERSION,
    description="Sistema de programacion de pulseras LED",
)

# CORS - permitir llamadas desde cualquier IP (red interna)
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_methods=["*"],
    allow_headers=["*"],
)

# Routers
app.include_router(pos.router)
app.include_router(sessions.router)
app.include_router(hardware.router)
app.include_router(agents.router)
app.include_router(sync.router)
app.include_router(health.router)
app.include_router(auth_local.router)
app.include_router(odoo.router)
app.include_router(terminals.router)
app.include_router(supervisor.router)

# Static files (POS interface)
import sys
_base = getattr(sys, '_MEIPASS', os.path.dirname(__file__))
static_dir = os.path.join(_base, "static")
app.mount("/static", StaticFiles(directory=static_dir), name="static")


@app.get("/")
def root():
    """Redirige a la interfaz POS."""
    return RedirectResponse(url="/static/pos.html")


@app.on_event("startup")
def startup():
    """Inicializa DB, seed de paquetes, carga agents, publica mDNS."""
    init_db()
    db = SessionLocal()
    try:
        # Seed paquetes
        existing = db.query(Package).count()
        if existing == 0:
            for pkg in DEFAULT_PACKAGES:
                db.add(Package(**pkg))
            db.commit()
            print(f"[DB] {len(DEFAULT_PACKAGES)} paquetes creados")
        else:
            print(f"[DB] {existing} paquetes existentes")

        # Sync paquetes al cloud (para que el panel Operator los vea)
        all_packages = db.query(Package).all()
        for pkg in all_packages:
            db.add(SyncQueue(
                table_name='packages',
                record_id=pkg.id,
                action='sync',
                payload=json.dumps({
                    'id': pkg.id,
                    'name': pkg.name,
                    'minutes': pkg.minutes,
                    'price': pkg.price,
                    'color': pkg.color,
                    'active': pkg.active,
                }),
            ))
        db.commit()
        print(f"[Sync] {len(all_packages)} paquete(s) en cola de sync al cloud")

        # Sync combos al cloud (para que el panel Operator los vea)
        from config import VENUE_ID
        all_combos = db.query(ComboRegistry).all()
        for combo in all_combos:
            db.add(SyncQueue(
                table_name='combo_registry',
                record_id=combo.combo_id,
                action='insert',
                payload=json.dumps({
                    'combo_id': combo.combo_id,
                    'agent_id': combo.agent_id,
                    'venue_id': combo.venue_id or VENUE_ID,
                }),
            ))
        if all_combos:
            db.commit()
            print(f"[Sync] {len(all_combos)} combo(s) en cola de sync al cloud")

        # Cargar agents registrados de la DB al diccionario en memoria
        agents_db = db.query(Agent).all()
        for a in agents_db:
            REGISTERED_AGENTS[a.id] = {"host": a.host, "port": a.port}
        if agents_db:
            print(f"[Agents] {len(agents_db)} agent(s) cargados de la DB")
        else:
            print(f"[Agents] Ningun agent registrado (esperando registro via POST /api/agents/register)")
    finally:
        db.close()

    # Uptime tracking
    health.set_start_time()

    # mDNS
    publish_service()

    print(f"\n{'='*50}")
    print(f"  ICEBERG Manillas POS - {VENUE_NAME}")
    print(f"  http://localhost:{SERVER_PORT}")
    print(f"  API docs: http://localhost:{SERVER_PORT}/docs")
    print(f"{'='*50}\n")


async def check_agents_heartbeat():
    """Background task: marca agents como offline si no hay heartbeat en 60seg."""
    while True:
        await asyncio.sleep(HEARTBEAT_CHECK_INTERVAL)
        cutoff = datetime.now() - timedelta(seconds=HEARTBEAT_TIMEOUT)
        db = SessionLocal()
        try:
            stale = db.query(Agent).filter(
                Agent.status == 'online',
                Agent.last_heartbeat < cutoff
            ).all()
            for a in stale:
                a.status = 'offline'
                REGISTERED_AGENTS.pop(a.id, None)
                # Sync estado offline al cloud
                db.add(SyncQueue(
                    table_name='agents',
                    record_id=a.id,
                    action='status_update',
                    payload=json.dumps({
                        'id': a.id, 'name': a.name, 'status': 'offline',
                        'last_heartbeat': a.last_heartbeat.isoformat() if a.last_heartbeat else None,
                    }),
                ))
                print(f"[Agents] {a.id} marcado offline (sin heartbeat >{ HEARTBEAT_TIMEOUT}seg)")
            if stale:
                db.commit()
        except Exception as e:
            print(f"[Agents] Error en heartbeat check: {e}")
        finally:
            db.close()


@app.on_event("startup")
async def start_background_tasks():
    """Inicia los background tasks."""
    asyncio.create_task(check_agents_heartbeat())
    asyncio.create_task(sync_worker())
    asyncio.create_task(cloud_poller())


@app.on_event("shutdown")
def shutdown():
    """Limpia mDNS al apagar."""
    unpublish_service()
