"""Discovery — recherche de prospects via Firecrawl SDK (API v2)."""

from __future__ import annotations

from dataclasses import dataclass
from urllib.parse import urlparse

import structlog
from firecrawl import AsyncFirecrawl
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception

from src.config import get_excluded_domains, get_settings

log = structlog.get_logger()


@dataclass(frozen=True)
class SearchResult:
    """Résultat de recherche Firecrawl."""
    url: str
    title: str
    domain: str
    description: str


def _extract_domain(url: str) -> str:
    """Extrait le domaine d'une URL."""
    parsed = urlparse(url)
    hostname = parsed.hostname or ""
    if hostname.startswith("www."):
        hostname = hostname[4:]
    return hostname


def _is_excluded(domain: str) -> bool:
    """Vérifie si un domaine est dans la liste d'exclusion (match exact ou sous-domaine)."""
    excluded = get_excluded_domains()
    # Match exact
    if domain in excluded:
        return True
    # Sous-domaine : fr.linkedin.com → linkedin.com
    parts = domain.split(".")
    for i in range(1, len(parts)):
        parent = ".".join(parts[i:])
        if parent in excluded:
            return True
    return False


def _get_firecrawl_client() -> AsyncFirecrawl:
    """Crée un client Firecrawl async configuré."""
    settings = get_settings()
    return AsyncFirecrawl(
        api_key=settings.firecrawl_api_key,
        api_url=settings.firecrawl_base_url,
    )


@retry(
    stop=stop_after_attempt(3),
    wait=wait_exponential(multiplier=2, min=2, max=10),
    retry=retry_if_exception(lambda e: not isinstance(e, KeyboardInterrupt)),
    reraise=True,
)
async def _firecrawl_search(
    client: AsyncFirecrawl,
    query: str,
    limit: int,
) -> list[dict]:
    """Appelle Firecrawl search via SDK (API v2)."""
    result = await client.search(query, limit=limit)
    # Le SDK v2 retourne SearchData avec .web (liste de SearchResultWeb)
    items = getattr(result, "web", None) or []
    return [
        {
            "url": getattr(item, "url", "") or "",
            "title": getattr(item, "title", "") or "",
            "description": getattr(item, "description", "") or "",
        }
        for item in items
    ]


async def search_prospects(
    niche: str,
    region: str,
    queries: list[str],
    limit: int = 100,
) -> list[SearchResult]:
    """Recherche des prospects pour une niche et région données.

    Exécute toutes les queries de la niche et déduplique par domaine.
    """
    seen_domains: set[str] = set()
    results: list[SearchResult] = []
    client = _get_firecrawl_client()

    for query_template in queries:
        if len(results) >= limit:
            break

        query = query_template.format(region=region)
        remaining = limit - len(results)

        log.info(
            "discovery.search",
            niche=niche,
            region=region,
            query=query,
            remaining=remaining,
        )

        try:
            raw_results = await _firecrawl_search(client, query, remaining)
        except Exception:
            log.exception("discovery.search_failed", query=query)
            continue

        for item in raw_results:
            url = item.get("url", "")
            domain = _extract_domain(url)
            if not domain or domain in seen_domains:
                continue

            if _is_excluded(domain):
                log.info("discovery.excluded", domain=domain)
                continue

            seen_domains.add(domain)
            results.append(SearchResult(
                url=url,
                title=item.get("title", ""),
                domain=domain,
                description=item.get("description", ""),
            ))

            if len(results) >= limit:
                break

    log.info("discovery.done", niche=niche, region=region, results=len(results))
    return results
