"""CLI Typer — point d'entrée du pipeline de génération de leads."""

from __future__ import annotations

import asyncio
from pathlib import Path
from typing import Annotated, Optional

import typer
from rich.console import Console
from rich.table import Table

from src.config import get_niches_config
from src.log import configure_logging

app = typer.Typer(
    name="lead-pipeline",
    help="Pipeline de génération de leads — Discovery, Enrichment, Scoring, Baserow Sync.",
    no_args_is_help=True,
)
console = Console()


@app.command()
def run(
    niche: Annotated[str, typer.Option(help="Niche cible (ex: piscines)")],
    region: Annotated[str, typer.Option(help="Région cible (ex: Bretagne)")],
    limit: Annotated[int, typer.Option(help="Nombre max de leads par run")] = 100,
    dry_run: Annotated[bool, typer.Option("--dry-run", help="Affiche sans pousser dans Baserow")] = False,
    concurrency: Annotated[int, typer.Option(help="Nombre de requêtes async parallèles")] = 10,
) -> None:
    """Exécute le pipeline pour une niche et une région."""
    configure_logging()

    # Validation niche & région
    config = get_niches_config()
    available_niches = list(config.niches.keys())
    if niche not in available_niches:
        console.print(f"[red]Niche inconnue : {niche!r}. Disponibles : {available_niches}[/red]")
        raise typer.Exit(1)

    available_regions = config.regions
    if region not in available_regions:
        console.print(f"[red]Région inconnue : {region!r}. Disponibles : {available_regions}[/red]")
        raise typer.Exit(1)

    from src.pipeline import run_pipeline

    stats = asyncio.run(run_pipeline(
        niche=niche,
        region=region,
        limit=limit,
        dry_run=dry_run,
        concurrency=concurrency,
    ))

    console.print()
    console.print(f"[bold green]Pipeline terminé[/bold green]")
    console.print(f"  Découverts : {stats.discovered}")
    console.print(f"  Skippés (dedup) : {stats.skipped_dedup}")
    console.print(f"  Enrichis : {stats.enriched}")
    console.print(f"  Qualifiés : {stats.qualified}")
    console.print(f"  Rejetés : {stats.rejected}")
    if not dry_run:
        console.print(f"  Syncés Baserow : {stats.synced}")
        if stats.sync_errors:
            console.print(f"  [red]Erreurs sync : {stats.sync_errors}[/red]")


@app.command()
def status() -> None:
    """Affiche le statut des domaines traités."""
    configure_logging()

    from src.db import get_processed_count, get_recent_domains

    count = asyncio.run(get_processed_count())
    recent = asyncio.run(get_recent_domains(limit=20))

    console.print(f"\n[bold]Domaines traités :[/bold] {count}\n")

    if recent:
        table = Table(title="Derniers domaines traités")
        table.add_column("Domaine", style="cyan")
        table.add_column("Date de traitement")

        for domain, processed_at in recent:
            table.add_row(domain, processed_at)

        console.print(table)
    else:
        console.print("[dim]Aucun domaine traité pour le moment.[/dim]")


@app.command(name="run-all")
def run_all(
    limit_per_niche: Annotated[int, typer.Option(help="Nombre max de leads par niche×région")] = 20,
    dry_run: Annotated[bool, typer.Option("--dry-run", help="Affiche sans pousser dans Baserow")] = False,
    concurrency: Annotated[int, typer.Option(help="Nombre de requêtes async parallèles")] = 10,
) -> None:
    """Exécute le pipeline pour toutes les niches et toutes les régions."""
    configure_logging()
    config = get_niches_config()

    from src.pipeline import run_pipeline

    total_qualified = 0
    total_synced = 0

    for niche in config.niches:
        for region in config.regions:
            console.print(f"\n[bold]→ {niche} × {region}[/bold]")
            stats = asyncio.run(run_pipeline(
                niche=niche,
                region=region,
                limit=limit_per_niche,
                dry_run=dry_run,
                concurrency=concurrency,
            ))
            total_qualified += stats.qualified
            total_synced += stats.synced

    console.print(f"\n[bold green]Tous les runs terminés.[/bold green]")
    console.print(f"  Total qualifiés : {total_qualified}")
    if not dry_run:
        console.print(f"  Total syncés : {total_synced}")


@app.command(name="sync-espo")
def sync_espo(
    dry_run: Annotated[bool, typer.Option("--dry-run", help="Affiche sans créer dans EspoCRM")] = False,
    limit: Annotated[int, typer.Option(help="Nombre max de leads à synchroniser")] = 500,
) -> None:
    """Synchronise les leads Baserow vers EspoCRM."""
    configure_logging()
    from src.config import get_settings

    settings = get_settings()
    if not settings.espocrm_url or not settings.espocrm_api_key:
        console.print("[red]ESPOCRM_URL et ESPOCRM_API_KEY requis dans .env[/red]")
        raise typer.Exit(1)

    from scripts.sync_baserow_espocrm import sync_baserow_to_espocrm

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


@app.command(name="sync-resend")
def sync_resend(
    dry_run: Annotated[bool, typer.Option("--dry-run", help="Affiche sans modifier EspoCRM/Baserow")] = False,
) -> None:
    """Sync events Resend → Dead (bounce) + Contacted (delivered) dans EspoCRM + Baserow."""
    configure_logging()
    from src.config import get_settings

    settings = get_settings()
    if not settings.resend_api_key:
        console.print("[red]RESEND_API_KEY requis dans .env[/red]")
        raise typer.Exit(1)

    from scripts.sync_bounces import sync_bounces as _sync

    stats = asyncio.run(_sync(dry_run=dry_run))
    console.print(f"\n[bold]Résultat sync-resend :[/bold]")
    console.print(f"  Emails Resend : {stats['total_emails']}")
    console.print(f"  Déjà en cache : {stats['cached']}")
    console.print(f"  Nouveaux : {stats['new_emails']}")
    console.print(f"  Bounced/suppressed : {stats['bounced']}")
    console.print(f"  Delivered/opened : {stats['contacted']}")
    console.print(f"  EspoCRM → Dead : {stats['espo_dead']}")
    console.print(f"  EspoCRM → Contacted : {stats['espo_contacted']}")
    console.print(f"  Baserow → Dead : {stats['baserow_dead']}")
    console.print(f"  Baserow → Contacted : {stats['baserow_contacted']}")
    console.print(f"  Déjà Dead : {stats['already_dead']}")
    console.print(f"  Déjà Contacted : {stats['already_contacted']}")
    console.print(f"  Non trouvés : {stats['not_found']}")
    if stats['errors']:
        console.print(f"  [red]Erreurs : {stats['errors']}[/red]")


@app.command(name="find-emails")
def find_emails(
    dry_run: Annotated[bool, typer.Option("--dry-run", help="Affiche sans modifier EspoCRM")] = False,
    limit: Annotated[int, typer.Option(help="Nombre max de leads à traiter")] = 500,
    thorough: Annotated[bool, typer.Option("--thorough", help="Reacher : ~60+ variantes par lead")] = False,
    concurrency: Annotated[int, typer.Option(help="Leads traités en parallèle")] = 3,
    local: Annotated[bool, typer.Option("--local", help="Reacher Docker local")] = False,
    backend: Annotated[str, typer.Option(help="Backend : reacher ou sleuth")] = "reacher",
    mode: Annotated[str, typer.Option(help="Mode sleuth : basic, enhanced, comprehensive")] = "enhanced",
) -> None:
    """Cherche les emails des leads Researching — met à jour EspoCRM."""
    configure_logging()
    from src.config import get_reacher_config, get_settings

    settings = get_settings()
    if not settings.espocrm_url or not settings.espocrm_api_key:
        console.print("[red]ESPOCRM_URL et ESPOCRM_API_KEY requis dans .env[/red]")
        raise typer.Exit(1)

    if backend == "sleuth":
        import shutil
        if not shutil.which("es") and not shutil.which("email-sleuth"):
            console.print("[red]email-sleuth non installé. Installe-le : https://github.com/buyukakyuz/email-sleuth/releases[/red]")
            raise typer.Exit(1)
        console.print(f"[bold]Backend sleuth[/bold] mode={mode}")
    else:
        rcfg = get_reacher_config(local=local)
        if not rcfg["url"]:
            env_prefix = "REACHER_URL_LOCAL" if local else "REACHER_URL"
            console.print(f"[red]{env_prefix} requis dans .env[/red]")
            raise typer.Exit(1)
        env_label = "local" if local else "distant"
        console.print(f"[bold]Backend reacher ({env_label})[/bold] → {rcfg['url']}")

    from scripts.find_emails_espo import find_emails as _find

    stats = asyncio.run(_find(
        dry_run=dry_run,
        limit=limit,
        thorough=thorough,
        concurrency=concurrency,
        local=local,
        backend=backend,
        sleuth_mode=mode,
    ))

    label_parts = [f"find-emails [{backend}]"]
    if backend == "sleuth":
        label_parts.append(f"mode={mode}")
    if thorough:
        label_parts.append("(thorough)")
    if local:
        label_parts.append("[local]")
    console.print(f"\n[bold]Résultat {' '.join(label_parts)}:[/bold]")
    console.print(f"  Leads Researching : {stats['total_researching']}")
    console.print(f"  Sans email : {stats['without_email']}")
    console.print(f"  Sans nom (skip permus) : {stats['without_name']}")
    if stats['reacher_checks']:
        console.print(f"  Checks Reacher : {stats['reacher_checks']}")
    console.print(f"  [green]Trouvés nominatifs : {stats['email_found_nominative']}[/green]")
    console.print(f"  [green]Trouvés génériques : {stats['email_found_generic']}[/green]")
    console.print(f"  Catch-all : {stats['catch_all']}")
    console.print(f"  Non trouvés : {stats['not_found']}")
    console.print(f"  [bold green]EspoCRM → Planned : {stats['updated_espo']}[/bold green]")
    if stats['errors']:
        console.print(f"  [red]Erreurs : {stats['errors']}[/red]")


@app.command(name="enrich-names")
def enrich_names(
    dry_run: Annotated[bool, typer.Option("--dry-run", help="Affiche sans modifier EspoCRM/Baserow")] = False,
    limit: Annotated[int, typer.Option(help="Nombre max de leads à traiter")] = 500,
    debug: Annotated[bool, typer.Option("--debug", help="Logs debug détaillés (API responses, Claude raw)")] = False,
) -> None:
    """Enrichit les noms des leads Researching — API entreprises + Claude Haiku fallback."""
    configure_logging()
    from src.config import get_settings

    settings = get_settings()
    if not settings.espocrm_url or not settings.espocrm_api_key:
        console.print("[red]ESPOCRM_URL et ESPOCRM_API_KEY requis dans .env[/red]")
        raise typer.Exit(1)

    console.print("[bold]Enrich names[/bold] — API Recherche d'entreprises + Claude Haiku fallback")
    if debug:
        console.print("  [dim]Mode debug activé[/dim]")
    if dry_run:
        console.print("  [dim]Mode dry-run — pas de modifications[/dim]")

    from scripts.enrich_names_espo import enrich_names as _enrich

    stats = asyncio.run(_enrich(dry_run=dry_run, limit=limit, debug=debug))

    console.print(f"\n[bold]Résultat enrich-names :[/bold]")
    console.print(f"  Leads Researching : {stats.total_researching}")
    console.print(f"  Sans vrai nom : {stats.without_real_name}")
    console.print(f"  Déjà nommés (skip) : {stats.skipped_already_named}")
    console.print(f"  [green]API entreprises → trouvés : {stats.api_found}[/green]")
    console.print(f"  API entreprises → pas trouvés : {stats.api_no_result}")
    console.print(f"  [green]Claude Haiku → trouvés : {stats.claude_found}[/green]")
    console.print(f"  Claude Haiku → pas trouvés : {stats.claude_no_result}")
    console.print(f"  [bold green]EspoCRM mis à jour : {stats.updated_espo}[/bold green]")
    console.print(f"  Baserow mis à jour : {stats.updated_baserow}")
    if stats.errors:
        console.print(f"  [red]Erreurs : {stats.errors}[/red]")


@app.command(name="run-auto")
def run_auto(
    daily_target: Annotated[int, typer.Option(help="Nombre de leads synced visé par jour")] = 100,
    batch_size: Annotated[int, typer.Option(help="Leads par batch")] = 50,
    workers: Annotated[int, typer.Option(help="Nombre de pipelines en parallèle")] = 3,
    concurrency: Annotated[int, typer.Option(help="Nombre de requêtes async parallèles par pipeline")] = 10,
    dry_run: Annotated[bool, typer.Option("--dry-run", help="Affiche sans pousser dans Baserow")] = False,
) -> None:
    """Mode autonome — tourne sur toutes les niches/régions jusqu'au daily target."""
    configure_logging()
    asyncio.run(_run_auto_async(
        daily_target=daily_target,
        batch_size=batch_size,
        workers=workers,
        concurrency=concurrency,
        dry_run=dry_run,
    ))


async def _run_auto_async(
    daily_target: int,
    batch_size: int,
    workers: int,
    concurrency: int,
    dry_run: bool,
) -> None:
    config = get_niches_config()

    from src.db import get_today_synced_count, get_coverage_stats, init_db
    from src.pipeline import run_pipeline

    await init_db()

    today_synced = await get_today_synced_count()
    if today_synced >= daily_target:
        console.print(f"[green]Target atteint ({today_synced}/{daily_target} synced aujourd'hui).[/green]")
        return

    remaining = daily_target - today_synced
    console.print(f"[bold]Mode auto — target {daily_target}, déjà synced {today_synced}, reste {remaining} (workers={workers})[/bold]\n")

    # Toutes les combinaisons niche × region, triées par couverture ASC
    all_combos = [(n, r) for n in config.niches for r in config.regions]
    coverage = await get_coverage_stats()
    all_combos.sort(key=lambda c: coverage.get(c, 0))

    total_synced_this_run = 0
    i = 0

    while i < len(all_combos) and total_synced_this_run < remaining:
        # Prendre un groupe de `workers` combinaisons
        group = []
        while len(group) < workers and i < len(all_combos) and total_synced_this_run + len(group) * batch_size < remaining + batch_size:
            group.append(all_combos[i])
            i += 1

        batch_limit = min(batch_size, remaining - total_synced_this_run)
        labels = [f"{n} × {r}" for n, r in group]
        console.print(f"\n[bold]→ Lancement parallèle ({len(group)} pipelines) :[/bold] {', '.join(labels)}")

        tasks = [
            run_pipeline(
                niche=niche,
                region=region,
                limit=batch_limit,
                dry_run=dry_run,
                concurrency=concurrency,
            )
            for niche, region in group
        ]
        results = await asyncio.gather(*tasks, return_exceptions=True)

        for (niche, region), result in zip(group, results):
            if isinstance(result, Exception):
                console.print(f"  [red]{niche} × {region} — erreur : {result}[/red]")
                continue
            total_synced_this_run += result.synced
            console.print(
                f"  {niche} × {region} — "
                f"qualifiés={result.qualified} synced={result.synced} "
                f"rejetés={result.rejected} dedup={result.skipped_dedup}"
            )

    console.print(f"\n[bold green]Auto terminé — {total_synced_this_run} synced ce run.[/bold green]")
    final_today = await get_today_synced_count()
    console.print(f"  Total aujourd'hui : {final_today}/{daily_target}")


@app.command(name="clean-statuses")
def clean_statuses(
    dry_run: Annotated[bool, typer.Option("--dry-run", help="Affiche sans modifier EspoCRM")] = False,
    cooldown_days: Annotated[int, typer.Option(help="Jours avant de recycler un lead Recycled")] = 90,
) -> None:
    """Nettoie les statuts EspoCRM : New sans email → Researching, Recycled > 90j → Planned."""
    configure_logging()
    from src.config import get_settings

    settings = get_settings()
    if not settings.espocrm_url or not settings.espocrm_api_key:
        console.print("[red]ESPOCRM_URL et ESPOCRM_API_KEY requis dans .env[/red]")
        raise typer.Exit(1)

    from scripts.clean_espo_statuses import clean_statuses as _clean, _load_bounced_emails

    async def _run() -> dict[str, int]:
        bounced = await _load_bounced_emails()
        if bounced:
            console.print(f"  Emails bounced Resend chargés : {len(bounced)}")
        return await _clean(dry_run=dry_run, cooldown_days=cooldown_days, bounced_emails=bounced)

    stats = asyncio.run(_run())

    console.print(f"\n[bold]Résultat clean statuses :[/bold]")
    console.print(f"  Leads New trouvés : {stats['new_total']}")
    console.print(f"  New → Researching (sans email) : {stats['new_to_researching']}")
    console.print(f"  New → Planned (avec email) : {stats['new_to_planned']}")
    console.print(f"  Leads Recycled trouvés : {stats['recycled_total']}")
    console.print(f"  Recycled → Planned : {stats['recycled_to_planned']}")
    console.print(f"  Recycled → Researching : {stats['recycled_to_researching']}")
    console.print(f"  Recycled → Dead (bounced) : {stats['recycled_to_dead']}")
    console.print(f"  Recycled trop récents (< {cooldown_days}j) : {stats['recycled_too_recent']}")
    if stats['errors']:
        console.print(f"  [red]Erreurs : {stats['errors']}[/red]")


@app.command(name="run-daily")
def run_daily(
    daily_target: Annotated[int, typer.Option(help="Leads synced visé (run-auto)")] = 200,
    workers: Annotated[int, typer.Option(help="Pipelines niche×région en parallèle")] = 1,
    concurrency: Annotated[int, typer.Option(help="Leads enrichis en parallèle par pipeline")] = 3,
    email_limit: Annotated[int, typer.Option(help="Limite pour enrich-names et find-emails")] = 500,
    email_backend: Annotated[str, typer.Option(help="Backend email : reacher ou sleuth")] = "reacher",
    email_mode: Annotated[str, typer.Option(help="Mode sleuth : basic, enhanced, comprehensive")] = "enhanced",
    email_concurrency: Annotated[int, typer.Option(help="Leads en parallèle (find-emails)")] = 3,
    dry_run: Annotated[bool, typer.Option("--dry-run", help="Pas de modifications")] = False,
    skip: Annotated[Optional[list[str]], typer.Option("--skip", help="Étapes à sauter (ex: --skip sync-resend)")] = None,
) -> None:
    """Orchestre toutes les étapes quotidiennes en séquence.

    Ordre : clean-statuses → run-auto → sync-espo → enrich-names → find-emails → sync-resend.
    Continue même si une étape échoue.
    """
    configure_logging()

    from scripts.run_daily import run_daily as _run, STEP_ORDER

    skip_set = set(skip) if skip else set()
    invalid = skip_set - set(STEP_ORDER)
    if invalid:
        console.print(f"[red]Étapes inconnues : {invalid}. Valides : {STEP_ORDER}[/red]")
        raise typer.Exit(1)

    console.print("[bold]═══ Run Daily ═══[/bold]")
    console.print(f"  Target: {daily_target} | Email: {email_backend} | Limit: {email_limit}")
    if skip_set:
        console.print(f"  Skip: {', '.join(skip_set)}")
    if dry_run:
        console.print("  [dim]Mode dry-run[/dim]")
    console.print()

    stats = asyncio.run(_run(
        daily_target=daily_target,
        workers=workers,
        concurrency=concurrency,
        email_limit=email_limit,
        email_backend=email_backend,
        email_mode=email_mode,
        email_concurrency=email_concurrency,
        dry_run=dry_run,
        skip=skip_set,
    ))

    # Résumé final
    console.print(f"\n[bold]═══ Résumé Daily ({_fmt_duration(stats.total_duration_s)}) ═══[/bold]\n")
    for step in stats.steps:
        if step.status == "ok":
            icon = "[green]✓[/green]"
            detail = f"[dim]({_fmt_duration(step.duration_s)})[/dim] {step.summary}"
        elif step.status == "error":
            icon = "[red]✗[/red]"
            detail = f"[red]({_fmt_duration(step.duration_s)}) {step.error}[/red]"
        else:
            icon = "[dim]–[/dim]"
            detail = "[dim]skippé[/dim]"
        console.print(f"  {icon} {step.name:20s} {detail}")

    ok_count = sum(1 for s in stats.steps if s.status == "ok")
    err_count = sum(1 for s in stats.steps if s.status == "error")
    total = len([s for s in stats.steps if s.status != "skipped"])

    if err_count:
        console.print(f"\n[bold yellow]{ok_count}/{total} étapes OK, {err_count} erreur(s)[/bold yellow]")
    else:
        console.print(f"\n[bold green]{ok_count}/{total} étapes OK[/bold green]")


def _fmt_duration(seconds: float) -> str:
    """Formatte une durée en format lisible."""
    if seconds < 60:
        return f"{seconds:.0f}s"
    minutes = int(seconds // 60)
    secs = int(seconds % 60)
    if minutes < 60:
        return f"{minutes}m{secs:02d}s"
    hours = minutes // 60
    mins = minutes % 60
    return f"{hours}h{mins:02d}m"


@app.command(name="import-csv")
def import_csv_cmd(
    csv_file: Annotated[Path, typer.Argument(help="Chemin vers le fichier CSV BuiltWith")],
    dry_run: Annotated[bool, typer.Option("--dry-run", help="Affiche sans créer dans Baserow")] = False,
    niche: Annotated[Optional[str], typer.Option(help="Override niche (ex: builtwith-import)")] = None,
    region: Annotated[Optional[str], typer.Option(help="Override région (ex: France)")] = None,
) -> None:
    """Importe un CSV BuiltWith dans Baserow — dedup automatique."""
    configure_logging()

    if not csv_file.exists():
        console.print(f"[red]Fichier introuvable : {csv_file}[/red]")
        raise typer.Exit(1)
    if not csv_file.suffix.lower() == ".csv":
        console.print(f"[red]Le fichier doit être un .csv : {csv_file}[/red]")
        raise typer.Exit(1)

    console.print(f"[bold]Import CSV[/bold] — {csv_file.name}")
    if dry_run:
        console.print("  [dim]Mode dry-run — pas de modifications[/dim]")
    if niche:
        console.print(f"  Niche override: {niche}")
    if region:
        console.print(f"  Region override: {region}")

    from scripts.import_csv import import_csv

    stats = asyncio.run(import_csv(
        csv_path=csv_file,
        dry_run=dry_run,
        niche_override=niche,
        region_override=region,
    ))

    console.print(f"\n[bold]Résultat import-csv :[/bold]")
    console.print(f"  Lignes CSV : {stats.total_rows}")
    if stats.skipped_invalid:
        console.print(f"  Invalides : {stats.skipped_invalid}")
    console.print(f"  Dedup SQLite : {stats.skipped_dedup_sqlite}")
    console.print(f"  Dedup Baserow : {stats.skipped_dedup_baserow}")
    console.print(f"  [green]Synced Baserow : {stats.synced}[/green]")
    if stats.synced_with_email:
        console.print(f"    dont avec email : {stats.synced_with_email}")
    if stats.sync_errors:
        console.print(f"  [red]Erreurs : {stats.sync_errors}[/red]")


@app.command(name="init-baserow")
def init_baserow() -> None:
    """Crée les options Single Select manquantes dans Baserow (niches, régions, CWV, etc.)."""
    configure_logging()
    import httpx
    from src.config import get_settings, get_niches_config

    settings = get_settings()
    config = get_niches_config()

    if not settings.baserow_email or not settings.baserow_password:
        console.print("[red]BASEROW_EMAIL et BASEROW_PASSWORD requis dans .env[/red]")
        raise typer.Exit(1)

    # Login JWT
    console.print("Authentification Baserow (JWT)...")
    r = httpx.post(
        f"{settings.baserow_base_url}/api/user/token-auth/",
        json={"email": settings.baserow_email, "password": settings.baserow_password},
    )
    r.raise_for_status()
    jwt = r.json()["access_token"]
    headers = {"Authorization": f"JWT {jwt}"}

    # Charger les champs actuels
    r = httpx.get(
        f"{settings.baserow_base_url}/api/database/fields/table/{settings.baserow_table_id}/",
        headers=headers,
    )
    r.raise_for_status()
    all_fields = {f["name"]: f for f in r.json()}

    # Niches du CSV BuiltWith (import)
    from scripts.import_csv import VERTICAL_TO_NICHE
    builtwith_niches = sorted(set(VERTICAL_TO_NICHE.values()) | {"builtwith-import"})

    # Options attendues par champ Single Select
    expected: dict[str, list[str]] = {
        "Niche": list(config.niches.keys()) + builtwith_niches,
        "Region": config.regions + ["France"],
        "CWV": ["FAST", "AVERAGE", "SLOW"],
        "HTTPS": ["Yes", "No"],
        "Statut": ["New", "Researching", "Planned", "Contacted", "Won", "Dead"],
        "Email Confidence": ["high", "medium", "low", "catch-all"],
    }

    for field_name, values in expected.items():
        if field_name not in all_fields:
            console.print(f"  [yellow]Champ '{field_name}' non trouvé — skip[/yellow]")
            continue

        field = all_fields[field_name]
        field_id = field["id"]
        field_type = field["type"]

        # Étape 1 : Convertir text → single_select si nécessaire
        if field_type == "text":
            console.print(f"  [cyan]{field_name}[/cyan] — conversion text → single_select...")
            resp = httpx.patch(
                f"{settings.baserow_base_url}/api/database/fields/{field_id}/",
                headers=headers,
                json={"type": "single_select"},
                timeout=30.0,
            )
            if resp.status_code != 200:
                console.print(f"  [red]{field_name}[/red] — erreur conversion : {resp.status_code}: {resp.text[:200]}")
                continue
            field = resp.json()
            console.print(f"  [green]{field_name}[/green] — converti en single_select")
        elif field_type != "single_select":
            console.print(f"  [yellow]{field_name}[/yellow] — type '{field_type}' non géré, skip")
            continue

        # Étape 2 : Ajouter les options manquantes
        existing = {o["value"] for o in field.get("select_options", [])}
        missing = [v for v in values if v not in existing]

        if not missing:
            console.print(f"  [green]{field_name}[/green] — {len(existing)} options OK")
            continue

        options = list(field.get("select_options", []))
        for val in missing:
            options.append({"value": val, "color": "light-blue"})

        resp = httpx.patch(
            f"{settings.baserow_base_url}/api/database/fields/{field_id}/",
            headers=headers,
            json={"select_options": options},
            timeout=30.0,
        )
        if resp.status_code == 200:
            console.print(f"  [green]{field_name}[/green] — ajouté {len(missing)} options : {missing}")
        else:
            console.print(f"  [red]{field_name}[/red] — erreur {resp.status_code}: {resp.text[:200]}")

    console.print("\n[bold green]Init Baserow terminé.[/bold green]")


if __name__ == "__main__":
    app()
