"""PandaDoc Public API client for direct document verification."""

from __future__ import annotations

from dataclasses import dataclass
from typing import Any

from g_gremlin.base import (
    AuthenticationError,
    BaseIntegration,
    IntegrationError,
    RateLimitError,
    RetryConfig,
)
from g_gremlin.credentials import resolve_credentials
from g_gremlin.credentials.provider import CredentialProvider

DEFAULT_API_BASE = "https://api.pandadoc.com/public/v1"
DEFAULT_RETRY_CONFIG = RetryConfig(max_attempts=4, base_delay=1.0, max_delay=10.0)


class PandaDocError(RuntimeError):
    """Raised when PandaDoc API access fails."""


@dataclass(frozen=True)
class PandaDocDocumentSnapshot:
    details: dict[str, Any]
    fields: list[dict[str, Any]]


def resolve_pandadoc_credentials(
    credential_provider: CredentialProvider | None = None,
) -> dict[str, str]:
    provider = credential_provider or CredentialProvider()
    return resolve_credentials(
        "pandadoc",
        required_keys=["api_key"],
        optional_keys=["api_base"],
        credential_provider=provider,
    )


class PandaDocClient(BaseIntegration):
    SERVICE_NAME = "pandadoc"

    def __init__(
        self,
        *,
        api_key: str | None = None,
        api_base: str | None = None,
        credential_provider: CredentialProvider | None = None,
        retry_config: RetryConfig | None = None,
    ) -> None:
        super().__init__(
            credential_provider=credential_provider,
            default_retry_config=retry_config or DEFAULT_RETRY_CONFIG,
        )
        if api_key is None:
            creds = resolve_pandadoc_credentials(credential_provider)
            api_key = creds["api_key"]
            api_base = api_base or creds.get("api_base")
        self.api_key = str(api_key or "").strip()
        self.api_base = _normalize_api_base(api_base)

    def get_document_snapshot(self, document_id: str) -> PandaDocDocumentSnapshot:
        normalized_id = str(document_id or "").strip()
        if not normalized_id:
            raise PandaDocError("PandaDoc document ID is required.")
        details = self.get_document_details(normalized_id)
        fields = self.list_document_fields(normalized_id)
        return PandaDocDocumentSnapshot(details=details, fields=fields)

    def get_document_details(self, document_id: str) -> dict[str, Any]:
        payload = self._get_json(
            f"{self.api_base}/documents/{document_id}/details",
            allow_statuses=(),
        )
        if not isinstance(payload, dict):
            raise PandaDocError("PandaDoc document details payload was not an object.")
        return payload

    def list_document_fields(self, document_id: str) -> list[dict[str, Any]]:
        payload = self._get_json(
            f"{self.api_base}/documents/{document_id}/fields",
            allow_statuses=(404,),
        )
        if not payload:
            return []
        if isinstance(payload, list):
            return [item for item in payload if isinstance(item, dict)]
        if not isinstance(payload, dict):
            return []
        for key in ("results", "fields", "data"):
            raw_items = payload.get(key)
            if isinstance(raw_items, list):
                return [item for item in raw_items if isinstance(item, dict)]
        return []

    def _headers(self) -> dict[str, str]:
        return {
            "Authorization": f"API-Key {self.api_key}",
            "Accept": "application/json",
        }

    def _get_json(
        self,
        url: str,
        *,
        allow_statuses: tuple[int, ...],
    ) -> dict[str, Any] | list[Any]:
        try:
            response = self._get(
                url,
                headers=self._headers(),
                allow_statuses=allow_statuses,
            )
        except (AuthenticationError, RateLimitError, IntegrationError) as exc:
            raise PandaDocError(str(exc)) from exc
        if response.status_code in allow_statuses:
            return {}
        try:
            payload = response.json()
        except Exception as exc:
            raise PandaDocError(f"Failed to parse PandaDoc response from {url}: {exc}") from exc
        if isinstance(payload, (dict, list)):
            return payload
        raise PandaDocError(f"Unexpected PandaDoc response payload from {url}.")


def _normalize_api_base(value: Any) -> str:
    normalized = str(value or "").strip().rstrip("/")
    if not normalized:
        return DEFAULT_API_BASE
    return normalized


__all__ = [
    "DEFAULT_API_BASE",
    "PandaDocClient",
    "PandaDocDocumentSnapshot",
    "PandaDocError",
    "resolve_pandadoc_credentials",
]
