"""
sync_looker.py
--------------
Extrae el total de suscripciones activas desde Looker Studio
y lo guarda en PostgreSQL/MySQL.

INSTALACIÓN:
    pip install playwright psycopg2-binary sqlalchemy
    playwright install chromium

USO:
    # Primer uso: autenticarse manualmente (abre navegador visible)
    python sync_looker.py --login

    # Uso normal (headless, para cron)
    python sync_looker.py

CRON (diario a las 9am):
    0 9 * * * /usr/bin/python3 /ruta/sync_looker.py >> /var/log/sync_looker.log 2>&1
"""

import argparse
import logging
import re
from datetime import date
from pathlib import Path

from playwright.sync_api import sync_playwright
from sqlalchemy import create_engine, text

# ─────────────────────────────────────────────
# CONFIGURACIÓN
# ─────────────────────────────────────────────

LOOKER_URL = (
    "https://lookerstudio.google.com/reporting/"
    "16bf944f-8e67-4eec-a45c-99e602b33848/page/p_qtmey17qud"
)

# Archivo donde se guarda la sesión de Google (se crea en --login)
SESSION_FILE = Path(__file__).parent / "google_session.json"

# Conexión a tu base de datos
# PostgreSQL: "postgresql+psycopg2://usuario:password@host:5432/nombre_db"
# MySQL:      "mysql+pymysql://usuario:password@host:3306/nombre_db"
DB_URL = "postgresql+psycopg2://usuario:password@localhost:5432/mi_base"

DB_TABLE = "suscripciones_activas_historico"

# Tiempo máximo de espera para que cargue el panel (ms)
TIMEOUT_MS = 60_000

# ─────────────────────────────────────────────

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s"
)
log = logging.getLogger(__name__)


def login_manual():
    """
    Abre un navegador visible para que inicies sesión en Google.
    Guarda la sesión en SESSION_FILE para usos futuros.
    Solo necesitas correr esto una vez.
    """
    log.info("Abriendo navegador para login manual...")
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=False)
        context = browser.new_context()
        page = context.new_page()
        page.goto(LOOKER_URL)

        print("\n" + "="*50)
        print("Por favor, inicia sesión en Google en el navegador.")
        print("Cuando el panel de Looker Studio esté visible, presiona ENTER aquí.")
        print("="*50 + "\n")
        input()

        context.storage_state(path=str(SESSION_FILE))
        log.info(f"Sesión guardada en {SESSION_FILE}")
        browser.close()


def extraer_suscripciones() -> int:
    """
    Abre Looker Studio con la sesión guardada y extrae
    el número de suscripciones activas del panel.
    """
    if not SESSION_FILE.exists():
        raise FileNotFoundError(
            f"No se encontró {SESSION_FILE}. "
            "Ejecuta primero: python sync_looker.py --login"
        )

    log.info("Iniciando extracción headless...")
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        context = browser.new_context(
            storage_state=str(SESSION_FILE),
            # Resolución amplia para asegurar que el gráfico se renderice
            viewport={"width": 1600, "height": 900},
        )
        page = context.new_page()
        page.goto(LOOKER_URL, timeout=TIMEOUT_MS)

        # Esperar a que el panel termine de cargar
        # Looker Studio muestra un spinner mientras carga; esperamos a que desaparezca
        log.info("Esperando que cargue el panel...")
        page.wait_for_load_state("networkidle", timeout=TIMEOUT_MS)

        # ── Estrategia 1: buscar el número por el texto del tooltip/label ──
        # El gráfico muestra los valores como labels sobre la línea.
        # Buscamos el último valor visible (el más reciente).
        #
        # Ajusta el selector si es necesario inspeccionando el DOM del panel.
        # En Looker Studio los valores suelen estar en elementos <text> de SVG
        # o en divs con clase específica.

        total = None

        # Intento con elementos SVG text (común en gráficos de línea)
        labels = page.locator("svg text").all_text_contents()
        log.info(f"Textos SVG encontrados: {labels[:20]}")  # log primeros 20

        # Filtramos textos que parezcan números con puntos (ej: "20.675")
        numeros = []
        for label in labels:
            limpio = label.strip().replace("\xa0", "").replace(" ", "")
            if re.match(r"^\d{2}\.\d{3}$", limpio):  # formato: 20.675
                numeros.append(int(limpio.replace(".", "")))

        if numeros:
            total = max(numeros)  # tomamos el valor más alto visible (o el último)
            log.info(f"Números encontrados en SVG: {numeros}")
        else:
            # ── Estrategia 2: capturar screenshot para debug ──
            page.screenshot(path="/tmp/looker_debug.png", full_page=True)
            log.warning(
                "No se encontraron números en el SVG. "
                "Revisa /tmp/looker_debug.png para ver qué cargó el panel."
            )

        browser.close()

    if total is None:
        raise ValueError(
            "No se pudo extraer el número de suscripciones. "
            "Revisa /tmp/looker_debug.png y ajusta el selector."
        )

    log.info(f"Suscripciones activas extraídas: {total:,}")
    return total


def crear_tabla_si_no_existe(engine):
    ddl = f"""
        CREATE TABLE IF NOT EXISTS {DB_TABLE} (
            id          SERIAL PRIMARY KEY,
            fecha       DATE        NOT NULL UNIQUE,
            total       INTEGER     NOT NULL,
            creado_en   TIMESTAMP   DEFAULT NOW()
        );
    """
    with engine.connect() as conn:
        conn.execute(text(ddl))
        conn.commit()
    log.info(f"Tabla '{DB_TABLE}' lista.")


def guardar_en_db(engine, total: int):
    hoy = date.today()
    upsert = f"""
        INSERT INTO {DB_TABLE} (fecha, total)
        VALUES (:fecha, :total)
        ON CONFLICT (fecha)
        DO UPDATE SET total = EXCLUDED.total, creado_en = NOW();
    """
    with engine.connect() as conn:
        conn.execute(text(upsert), {"fecha": hoy, "total": total})
        conn.commit()
    log.info(f"Guardado: {hoy} → {total:,}")


def main(login: bool):
    if login:
        login_manual()
        return

    total = extraer_suscripciones()
    engine = create_engine(DB_URL)
    crear_tabla_si_no_existe(engine)
    guardar_en_db(engine, total)
    log.info("✅ Sincronización completada.")


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "--login",
        action="store_true",
        help="Autenticarse manualmente en Google (solo la primera vez)"
    )
    args = parser.parse_args()
    main(login=args.login)