"""Sync Baserow → EspoCRM — lit les leads Baserow et les pousse dans EspoCRM.

Usage :
    uv run python scripts/sync_baserow_espocrm.py [--dry-run] [--limit 50]
"""

from __future__ import annotations

import argparse
import asyncio
from urllib.parse import urlparse

import httpx
import structlog

from src.config import get_settings
from src.espocrm import build_espo_lead, create_lead, search_lead_by_website
from src.log import configure_logging

log = structlog.get_logger()


async def _fetch_baserow_leads(client: httpx.AsyncClient, limit: int) -> list[dict]:
    """Récupère les leads depuis Baserow (paginé)."""
    settings = get_settings()
    leads: list[dict] = []
    page_size = min(limit, 200)
    offset = 0

    while len(leads) < limit:
        resp = await client.get(
            f"{settings.baserow_base_url}/api/database/rows/table/{settings.baserow_table_id}/",
            headers={"Authorization": f"Token {settings.baserow_token}"},
            params={
                "user_field_names": "true",
                "size": page_size,
                "page": (offset // page_size) + 1,
            },
            timeout=30.0,
        )
        resp.raise_for_status()
        data = resp.json()
        results = data.get("results", [])
        if not results:
            break
        leads.extend(results)
        offset += len(results)
        if data.get("next") is None:
            break

    return leads[:limit]


def _extract_domain(url: str) -> str:
    """Extrait le domaine d'une URL pour le dedup."""
    try:
        parsed = urlparse(url)
        return parsed.netloc.removeprefix("www.")
    except Exception:
        return ""


async def sync_baserow_to_espocrm(dry_run: bool = False, limit: int = 500) -> None:
    """Sync principal : lit Baserow → vérifie dedup EspoCRM → crée les nouveaux leads."""
    settings = get_settings()

    if not settings.espocrm_url or not settings.espocrm_api_key:
        log.error("sync.missing_config", msg="ESPOCRM_URL et ESPOCRM_API_KEY requis dans .env")
        return

    stats = {"total": 0, "skipped_no_data": 0, "skipped_exists": 0, "created": 0, "errors": 0}

    async with httpx.AsyncClient() as client:
        # 1. Charger les leads Baserow
        log.info("sync.fetch_baserow", limit=limit)
        rows = await _fetch_baserow_leads(client, limit)
        stats["total"] = len(rows)
        log.info("sync.baserow_loaded", count=len(rows))

        # 2. Pour chaque lead, vérifier et pousser
        for row in rows:
            website = (row.get("Website") or "").strip()
            domain = row.get("Domaine") or _extract_domain(website)

            # Construire le payload EspoCRM
            payload = build_espo_lead(row)
            if payload is None:
                stats["skipped_no_data"] += 1
                log.debug("sync.skip_no_data", domain=domain)
                continue

            # Dedup : vérifier si le lead existe déjà dans EspoCRM
            try:
                existing = await search_lead_by_website(client, domain)
                if existing:
                    stats["skipped_exists"] += 1
                    log.debug("sync.skip_exists", domain=domain, espo_id=existing[0].get("id"))
                    continue
            except Exception as exc:
                log.warning("sync.search_error", domain=domain, error=str(exc))
                # En cas d'erreur de recherche, on skip pour éviter les doublons
                stats["errors"] += 1
                continue

            # Créer dans EspoCRM
            if dry_run:
                stats["created"] += 1
                log.info("sync.dry_run_create", domain=domain, payload=payload)
                continue

            try:
                result = await create_lead(client, payload)
                stats["created"] += 1
                log.info("sync.created", domain=domain, espo_id=result.get("id"))
            except Exception as exc:
                stats["errors"] += 1
                log.error("sync.create_error", domain=domain, error=str(exc))

    log.info("sync.done", **stats)
    print(f"\nSync terminé :")
    print(f"  Total Baserow : {stats['total']}")
    print(f"  Skippés (données manquantes) : {stats['skipped_no_data']}")
    print(f"  Skippés (déjà dans EspoCRM) : {stats['skipped_exists']}")
    print(f"  Créés dans EspoCRM : {stats['created']}")
    if stats["errors"]:
        print(f"  Erreurs : {stats['errors']}")


def main() -> None:
    parser = argparse.ArgumentParser(description="Sync Baserow → EspoCRM")
    parser.add_argument("--dry-run", action="store_true", help="Affiche sans créer dans EspoCRM")
    parser.add_argument("--limit", type=int, default=500, help="Nombre max de leads à traiter")
    args = parser.parse_args()

    configure_logging()
    asyncio.run(sync_baserow_to_espocrm(dry_run=args.dry_run, limit=args.limit))


if __name__ == "__main__":
    main()
