"""Pipeline orchestrateur — discovery → dedup → enrichment → scoring → sync."""

from __future__ import annotations

from dataclasses import dataclass
from datetime import datetime, timezone

import httpx
import structlog
from structlog.contextvars import bind_contextvars, unbind_contextvars

from src.config import get_niches_config, get_settings
from src.crm import sync_lead
from src.db import (
    get_processed_domains_with_status,
    increment_retry,
    init_db,
    mark_processed,
    record_daily_stats,
)
from src.discovery import search_prospects
from src.enrichment import EnrichedLead, enrich_batch
from src.scorer import ScoringResult, log_rejected, score_lead

log = structlog.get_logger()


@dataclass
class PipelineStats:
    """Statistiques d'un run de pipeline."""
    discovered: int = 0
    skipped_dedup: int = 0
    enriched: int = 0
    qualified: int = 0
    rejected: int = 0
    synced: int = 0
    sync_errors: int = 0


async def run_pipeline(
    niche: str,
    region: str,
    limit: int = 100,
    dry_run: bool = False,
    concurrency: int = 10,
) -> PipelineStats:
    """Exécute le pipeline complet pour une niche et une région."""
    stats = PipelineStats()
    config = get_niches_config()

    log.info("pipeline.start", niche=niche, region=region, limit=limit, dry_run=dry_run)

    # 0. Init DB
    await init_db()

    # 1. Discovery
    queries = config.get_queries(niche)
    results = await search_prospects(niche, region, queries, limit=limit)
    stats.discovered = len(results)

    if not results:
        log.warning("pipeline.no_results", niche=niche, region=region)
        return stats

    # 2. Dedup (status-aware: synced/rejected → skip, error+retry<3 → retry)
    domains_to_check = [r.domain for r in results]
    processed_map = await get_processed_domains_with_status(domains_to_check)

    new_results = []
    for result in results:
        info = processed_map.get(result.domain)
        if info is None:
            new_results.append(result)
            continue

        status, retry_count = info
        if status in ("synced", "rejected", "dead"):
            log.info("dedup.skip", domain=result.domain, reason=f"already_{status}")
            stats.skipped_dedup += 1
        elif status == "error" and retry_count >= 3:
            log.info("dedup.skip", domain=result.domain, reason="max_retries", retries=retry_count)
            stats.skipped_dedup += 1
        elif status == "error":
            log.info("dedup.retry", domain=result.domain, retry_count=retry_count + 1)
            await increment_retry(result.domain)
            new_results.append(result)
        else:
            new_results.append(result)

    if not new_results:
        log.info("pipeline.all_deduped", niche=niche, region=region)
        return stats

    # 3. Enrichment
    enriched_leads = await enrich_batch(new_results, niche, region, concurrency=concurrency)
    stats.enriched = len(enriched_leads)

    # 4. Scoring + 5. Sync
    scored: list[tuple[EnrichedLead, ScoringResult]] = []
    for lead in enriched_leads:
        scoring = score_lead(lead)
        if scoring.qualified:
            stats.qualified += 1
            scored.append((lead, scoring))
        else:
            stats.rejected += 1
            log_rejected(lead, scoring)
            await mark_processed(lead.domain, status="rejected")

    if dry_run:
        log.info(
            "pipeline.dry_run_done",
            discovered=stats.discovered,
            enriched=stats.enriched,
            qualified=stats.qualified,
            rejected=stats.rejected,
        )
        _print_dry_run_results(scored)
        return stats

    # 5. Baserow sync
    settings = get_settings()
    async with httpx.AsyncClient() as client:
        for lead, scoring in scored:
            bind_contextvars(lead_domain=lead.domain)
            try:
                row_id = await sync_lead(client, lead, scoring)
                # Marquer en SQLite SEULEMENT après confirmation Baserow
                await mark_processed(lead.domain)
                stats.synced += 1
                log.info("pipeline.lead_synced", domain=lead.domain, row_id=row_id, score=scoring.score)
            except Exception:
                stats.sync_errors += 1
                log.exception("pipeline.sync_failed", domain=lead.domain)
                await mark_processed(lead.domain, status="error")
            finally:
                unbind_contextvars("lead_domain")

    log.info(
        "pipeline.done",
        niche=niche,
        region=region,
        discovered=stats.discovered,
        skipped_dedup=stats.skipped_dedup,
        enriched=stats.enriched,
        qualified=stats.qualified,
        rejected=stats.rejected,
        synced=stats.synced,
        sync_errors=stats.sync_errors,
    )

    # Enregistrer les stats quotidiennes
    today = datetime.now(timezone.utc).strftime("%Y-%m-%d")
    await record_daily_stats(today, niche, region, stats.discovered, stats.qualified, stats.synced)

    return stats


def _print_dry_run_results(scored: list[tuple[EnrichedLead, ScoringResult]]) -> None:
    """Affiche les résultats qualifiés en mode dry-run."""
    from rich.console import Console
    from rich.table import Table

    console = Console()
    table = Table(title="Leads qualifiés (dry-run)")
    table.add_column("Domaine", style="cyan")
    table.add_column("Entreprise")
    table.add_column("Dirigeant")
    table.add_column("Score", justify="right", style="green")
    table.add_column("Tech")
    table.add_column("Perf", justify="right")
    table.add_column("SEO", justify="right")

    for lead, scoring in scored:
        director = f"{lead.director_first_name} {lead.director_last_name}".strip()
        perf = f"{round(lead.perf_score * 100)}%" if lead.perf_score is not None else "-"
        seo = f"{round(lead.seo_score * 100)}%" if lead.seo_score is not None else "-"
        table.add_row(
            lead.domain,
            lead.company_name or lead.title,
            director or "-",
            str(scoring.score),
            lead.technology or "-",
            perf,
            seo,
        )

    console.print(table)
