"""
Sync Worker - Envia registros pendientes de sync_queue al hosting cloud.
Corre como background task dentro de FastAPI.
"""
import asyncio
import httpx
import json
from datetime import datetime
from database import SessionLocal
from models import SyncQueue
from config import (
    CLOUD_SYNC_URL, CLOUD_SYNC_KEY, CLOUD_SYNC_INTERVAL,
    CLOUD_SYNC_BATCH_SIZE, VENUE_ID, APP_VERSION,
)

# URL del Operator API (misma base que el sync, pero en Operator/)
_OPERATOR_HEARTBEAT_URL = CLOUD_SYNC_URL.replace("Plan/api/sync.php", "Operator/api.php?action=server_heartbeat")

# Backoff exponencial: empieza en CLOUD_SYNC_INTERVAL, max 15 min
_current_interval = CLOUD_SYNC_INTERVAL
_max_interval = 900
_consecutive_errors = 0


async def sync_worker():
    """Background task: envia registros pendientes al cloud cada X segundos."""
    global _current_interval, _consecutive_errors

    # Esperar 10 seg al arrancar para que el server este listo
    await asyncio.sleep(10)
    print(f"[Sync Worker] Iniciado. URL: {CLOUD_SYNC_URL}")
    print(f"[Sync Worker] Intervalo: {CLOUD_SYNC_INTERVAL}seg, Lote: {CLOUD_SYNC_BATCH_SIZE}")

    while True:
        try:
            sent = await _process_batch()
            if sent > 0:
                # Exito: resetear backoff
                _current_interval = CLOUD_SYNC_INTERVAL
                _consecutive_errors = 0
                print(f"[Sync Worker] {sent} registro(s) sincronizados")
            # Si no hay nada pendiente, no imprime nada (silencioso)
        except Exception as e:
            _consecutive_errors += 1
            # Backoff exponencial
            _current_interval = min(
                CLOUD_SYNC_INTERVAL * (2 ** _consecutive_errors),
                _max_interval
            )
            print(f"[Sync Worker] Error ({_consecutive_errors}x): {e}. Reintentando en {_current_interval}seg")

        # Siempre enviar heartbeat del servidor al cloud
        await _send_server_heartbeat()

        await asyncio.sleep(_current_interval)


async def _process_batch():
    """Procesa un lote de registros pendientes. Retorna cantidad enviados."""
    db = SessionLocal()
    try:
        # Obtener registros no sincronizados
        pending = db.query(SyncQueue).filter(
            SyncQueue.synced == False
        ).limit(CLOUD_SYNC_BATCH_SIZE).all()

        if not pending:
            return 0

        # Preparar payload
        records = []
        for item in pending:
            records.append({
                "id": item.id,
                "table_name": item.table_name,
                "record_id": item.record_id,
                "action": item.action,
                "payload": item.payload,
                "created_at": item.created_at.isoformat() if item.created_at else None,
            })

        # Enviar al cloud
        async with httpx.AsyncClient(timeout=30.0) as client:
            resp = await client.post(
                CLOUD_SYNC_URL,
                json={
                    "venue_id": VENUE_ID,
                    "key": CLOUD_SYNC_KEY,
                    "records": records,
                },
            )

        if resp.status_code == 200:
            result = resp.json()
            if result.get("status") == "ok":
                # Marcar como sincronizados
                synced_ids = result.get("synced_ids", [r["id"] for r in records])
                for item in pending:
                    if item.id in synced_ids:
                        item.synced = True
                db.commit()
                return len(synced_ids)
            else:
                raise Exception(f"Cloud respondio: {result.get('message', 'error desconocido')}")
        else:
            raise Exception(f"HTTP {resp.status_code}: {resp.text[:200]}")

    finally:
        db.close()


async def _send_server_heartbeat():
    """Envia un heartbeat al Operator cloud para indicar que este servidor esta vivo."""
    try:
        async with httpx.AsyncClient(timeout=10.0) as client:
            resp = await client.post(
                _OPERATOR_HEARTBEAT_URL,
                json={
                    "venue_id": VENUE_ID,
                    "key": CLOUD_SYNC_KEY,
                    "app_version": APP_VERSION,
                },
            )
        if resp.status_code == 200:
            result = resp.json()
            if result.get("status") != "ok":
                print(f"[Heartbeat] Respuesta inesperada: {result}")
    except Exception as e:
        print(f"[Heartbeat] Error: {e}")
