"""EspoCRM — Client async pour le sync Baserow → EspoCRM."""

from __future__ import annotations

import json
from urllib.parse import quote

import httpx
import structlog
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception

from src.config import get_settings

log = structlog.get_logger()


def _is_retryable(exc: BaseException) -> bool:
    if isinstance(exc, (httpx.ConnectError, httpx.TimeoutException)):
        return True
    if isinstance(exc, httpx.HTTPStatusError) and exc.response.status_code >= 500:
        return True
    return False


def _headers() -> dict[str, str]:
    settings = get_settings()
    return {
        "X-Api-Key": settings.espocrm_api_key,
        "Content-Type": "application/json",
    }


def _base_url() -> str:
    return get_settings().espocrm_url.rstrip("/")


@retry(
    stop=stop_after_attempt(3),
    wait=wait_exponential(multiplier=2, min=2, max=10),
    retry=retry_if_exception(_is_retryable),
    reraise=True,
)
async def search_lead_by_website(client: httpx.AsyncClient, website: str) -> list[dict]:
    """Cherche un Lead dans EspoCRM par le champ website.

    Returns la liste des leads trouvés (vide si aucun).
    """
    params = {
        "where[0][type]": "contains",
        "where[0][attribute]": "website",
        "where[0][value]": website,
        "select": "id,firstName,lastName,website",
        "maxSize": "5",
    }
    resp = await client.get(
        f"{_base_url()}/api/v1/Lead",
        headers=_headers(),
        params=params,
        timeout=30.0,
    )
    resp.raise_for_status()
    data = resp.json()
    return data.get("list", [])


@retry(
    stop=stop_after_attempt(3),
    wait=wait_exponential(multiplier=2, min=2, max=10),
    retry=retry_if_exception(_is_retryable),
    reraise=True,
)
async def create_lead(client: httpx.AsyncClient, lead_data: dict) -> dict:
    """Crée un Lead dans EspoCRM.

    Payload = champs obligatoires uniquement.
    Returns les attributs du lead créé (incluant son id).
    """
    resp = await client.post(
        f"{_base_url()}/api/v1/Lead",
        headers={**_headers(), "X-Skip-Duplicate-Check": "true"},
        json=lead_data,
        timeout=30.0,
    )
    if resp.status_code >= 400:
        log.error("espocrm.create_error", status=resp.status_code, body=resp.text[:500])
    resp.raise_for_status()
    return resp.json()


def build_espo_lead(row: dict) -> dict | None:
    """Construit le payload EspoCRM à partir d'une row Baserow.

    Retourne None si les données obligatoires sont manquantes (pas de lastName).
    Champs mappés (obligatoires uniquement) :
    - lastName (requis par EspoCRM)
    - firstName
    - accountName (= Entreprise)
    - emailAddress (si présent)
    - website (= Website)
    - status = "Planned" si email présent, sinon "Researching"
    """
    last_name = (row.get("Nom") or "").strip()
    first_name = (row.get("Prenom") or "").strip()
    company = (row.get("Entreprise") or "").strip()
    website = (row.get("Website") or "").strip()
    email = (row.get("Email Contact") or "").strip()

    # EspoCRM exige lastName
    if not last_name:
        # Fallback : utiliser le nom de l'entreprise comme lastName
        if company:
            last_name = company
        else:
            return None

    payload: dict = {
        "lastName": last_name,
        "status": "Planned" if email else "Researching",
    }

    if first_name:
        payload["firstName"] = first_name
    if company:
        payload["accountName"] = company
    if website:
        payload["website"] = website
    if email:
        payload["emailAddress"] = email

    return payload
