"""Adobe Sign REST 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.na1.echosign.com/api/rest/v6"
DEFAULT_RETRY_CONFIG = RetryConfig(max_attempts=4, base_delay=1.0, max_delay=10.0)


class AdobeSignError(RuntimeError):
    """Raised when Adobe Sign API access fails."""


@dataclass(frozen=True)
class AdobeAgreementSnapshot:
    agreement: dict[str, Any]
    form_data: list[dict[str, Any]]


def resolve_adobe_sign_credentials(
    credential_provider: CredentialProvider | None = None,
) -> dict[str, str]:
    provider = credential_provider or CredentialProvider()
    return resolve_credentials(
        "adobe_sign",
        required_keys=["access_token"],
        optional_keys=["api_base", "api_access_point"],
        credential_provider=provider,
    )


class AdobeSignClient(BaseIntegration):
    SERVICE_NAME = "adobe_sign"

    def __init__(
        self,
        *,
        access_token: str | None = None,
        api_base: str | None = None,
        api_access_point: 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 access_token is None or api_base is None:
            creds = resolve_adobe_sign_credentials(credential_provider)
            access_token = access_token or creds["access_token"]
            api_base = api_base or creds.get("api_base") or creds.get("api_access_point")
            api_access_point = api_access_point or creds.get("api_access_point")
        self.access_token = str(access_token or "").strip()
        self.api_base = _normalize_api_base(api_base or api_access_point)

    def get_agreement_snapshot(self, agreement_id: str) -> AdobeAgreementSnapshot:
        normalized_id = str(agreement_id or "").strip()
        if not normalized_id:
            raise AdobeSignError("Adobe Sign agreement ID is required.")
        agreement = self.get_agreement(normalized_id)
        form_data = self.get_agreement_form_data(normalized_id)
        return AdobeAgreementSnapshot(agreement=agreement, form_data=form_data)

    def get_agreement(self, agreement_id: str) -> dict[str, Any]:
        payload = self._get_json(
            f"{self.api_base}/agreements/{agreement_id}",
            allow_statuses=(),
        )
        if not isinstance(payload, dict):
            raise AdobeSignError("Adobe Sign agreement payload was not an object.")
        return payload

    def get_agreement_form_data(self, agreement_id: str) -> list[dict[str, Any]]:
        payload = self._get_json(
            f"{self.api_base}/agreements/{agreement_id}/formData",
            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 ("formData", "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"Bearer {self.access_token}",
            "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 AdobeSignError(str(exc)) from exc
        if response.status_code in allow_statuses:
            return {}
        try:
            payload = response.json()
        except Exception as exc:
            raise AdobeSignError(f"Failed to parse Adobe Sign response from {url}: {exc}") from exc
        if isinstance(payload, (dict, list)):
            return payload
        raise AdobeSignError(f"Unexpected Adobe Sign response payload from {url}.")


def _normalize_api_base(value: Any) -> str:
    normalized = str(value or "").strip().rstrip("/")
    if not normalized:
        return DEFAULT_API_BASE
    if normalized.endswith("/api/rest/v6"):
        return normalized
    return f"{normalized}/api/rest/v6"


__all__ = [
    "AdobeAgreementSnapshot",
    "AdobeSignClient",
    "AdobeSignError",
    "DEFAULT_API_BASE",
    "resolve_adobe_sign_credentials",
]
