"""HubSpot CRM provider adapter with mock fallback."""

from __future__ import annotations

import os
from typing import Any

import requests

from kiessclaw.models.contact import Contact
from kiessclaw.providers.base import BaseProvider
from kiessclaw.providers.models import ProviderResult
from kiessclaw.providers.mock import MockProvider


class HubSpotProvider(BaseProvider):
    """HubSpot CRM provider implementation."""

    name = "hubspot"
    kind = "crm"

    def __init__(self, config: dict[str, Any] | None = None):
        """Initialize HubSpot adapter and fallback provider."""
        super().__init__(config)
        self.api_key = os.getenv("HUBSPOT_API_KEY", "").strip()
        self._fallback = MockProvider(config)
        self._base_url = "https://api.hubapi.com"

    def _headers(self) -> dict[str, str]:
        """Return HubSpot request headers."""
        return {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json",
        }

    def _properties_from_contact(self, contact: Contact) -> dict[str, Any]:
        """Map contact model fields to HubSpot contact properties."""
        return {
            "email": contact.email,
            "firstname": contact.first_name,
            "lastname": contact.last_name,
            "jobtitle": contact.title or "",
        }

    def create_contact(self, contact: Contact) -> ProviderResult:
        """Create or upsert one CRM contact."""
        if not self.api_key:
            return self._fallback.enrich_contact(contact.email)
        try:
            existing = self.find_contact(contact.email)
            properties = self._properties_from_contact(contact)
            if existing.ok and existing.data.get("id"):
                return self.update_contact(str(existing.data["id"]), properties)

            response = requests.post(
                f"{self._base_url}/crm/v3/objects/contacts",
                headers=self._headers(),
                json={"properties": properties},
                timeout=10,
            )
            response.raise_for_status()
            payload = response.json() if isinstance(response.json(), dict) else {}
            return ProviderResult(ok=True, data=payload, provider=self.name, confidence=0.8)
        except Exception as exc:  # noqa: BLE001
            return ProviderResult(ok=False, provider=self.name, error=str(exc), confidence=0.0)

    def update_contact(self, contact_id: str, props: dict[str, Any]) -> ProviderResult:
        """Update HubSpot contact properties by ID."""
        if not self.api_key:
            return ProviderResult(ok=True, data={"id": contact_id, "updated": False}, provider="mock", confidence=0.1)
        try:
            response = requests.patch(
                f"{self._base_url}/crm/v3/objects/contacts/{contact_id}",
                headers=self._headers(),
                json={"properties": props},
                timeout=10,
            )
            response.raise_for_status()
            payload = response.json() if isinstance(response.json(), dict) else {}
            return ProviderResult(ok=True, data=payload, provider=self.name, confidence=0.8)
        except Exception as exc:  # noqa: BLE001
            return ProviderResult(ok=False, provider=self.name, error=str(exc), confidence=0.0)

    def find_contact(self, email: str) -> ProviderResult:
        """Find one contact in HubSpot by email."""
        if not self.api_key:
            return self._fallback.enrich_contact(email)
        try:
            response = requests.get(
                f"{self._base_url}/crm/v3/objects/contacts",
                headers=self._headers(),
                params={"email": email},
                timeout=10,
            )
            if response.status_code == 404:
                return ProviderResult(ok=False, data={}, provider=self.name, error="Contact not found", confidence=0.0)
            response.raise_for_status()
            payload = response.json() if isinstance(response.json(), dict) else {}
            results = payload.get("results", [])
            if isinstance(results, list) and results:
                return ProviderResult(ok=True, data=results[0], provider=self.name, confidence=0.8)
            return ProviderResult(ok=False, data={}, provider=self.name, error="Contact not found", confidence=0.0)
        except Exception as exc:  # noqa: BLE001
            return ProviderResult(ok=False, provider=self.name, error=str(exc), confidence=0.0)

    def find_email(self, first: str, last: str, domain: str) -> ProviderResult:
        """HubSpot is not an email finder, so fallback to mock."""
        return self._fallback.find_email(first, last, domain)

    def enrich_contact(self, email: str) -> ProviderResult:
        """Enrich contact by retrieving CRM record details."""
        result = self.find_contact(email)
        if result.ok:
            return result
        if not self.api_key:
            return self._fallback.enrich_contact(email)
        return result

    def health_check(self) -> bool:
        """Return true when fallback is healthy or HubSpot endpoint responds."""
        if not self.api_key:
            return self._fallback.health_check()
        try:
            response = requests.get(
                f"{self._base_url}/crm/v3/objects/contacts",
                headers=self._headers(),
                params={"limit": 1},
                timeout=10,
            )
            return response.status_code < 500
        except Exception:  # noqa: BLE001
            return False
