"""Poke - Python SDK for the Poke API."""

from __future__ import annotations

__version__ = "0.1.1"

import json
import os
import platform
from pathlib import Path
from typing import Any, Dict, Optional
from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen

DEFAULT_BASE_URL = "https://poke.com/api/v1"


class PokeError(Exception):
    """Base exception for Poke SDK errors."""

    def __init__(self, message: str, status: Optional[int] = None):
        super().__init__(message)
        self.status = status


class AuthenticationError(PokeError):
    """Raised when the API key is invalid or expired."""


class ForbiddenError(PokeError):
    """Raised when the API key lacks required scopes."""


class RateLimitError(PokeError):
    """Raised when the API rate limit is exceeded."""


def _load_credentials_file() -> Optional[str]:
    config_home = os.environ.get("XDG_CONFIG_HOME")
    if config_home:
        creds_path = Path(config_home) / "poke" / "credentials.json"
    else:
        creds_path = Path.home() / ".config" / "poke" / "credentials.json"

    try:
        data = json.loads(creds_path.read_text())
        return data.get("token")
    except (FileNotFoundError, json.JSONDecodeError, KeyError):
        return None


def _resolve_api_key(api_key: Optional[str]) -> str:
    if api_key:
        return api_key

    env_key = os.environ.get("POKE_API_KEY")
    if env_key:
        return env_key

    file_key = _load_credentials_file()
    if file_key:
        return file_key

    raise PokeError(
        "No API key found. Pass api_key=, set POKE_API_KEY, "
        "or log in with the Poke CLI."
    )


def _resolve_base_url(base_url: Optional[str]) -> str:
    if base_url:
        return base_url.rstrip("/")
    env_url = os.environ.get("POKE_API")
    if env_url:
        return env_url.rstrip("/")
    return DEFAULT_BASE_URL


def _request(
    url: str,
    *,
    method: str = "POST",
    headers: Dict[str, str],
    data: Optional[Dict[str, Any]] = None,
) -> Dict[str, Any]:
    body = json.dumps(data).encode() if data is not None else None
    req = Request(url, data=body, headers=headers, method=method)

    try:
        with urlopen(req) as resp:
            return json.loads(resp.read().decode())
    except HTTPError as e:
        status = e.code
        try:
            detail = json.loads(e.read().decode())
            msg = detail.get("error") or detail.get("message") or ""
        except Exception:
            msg = e.reason

        if status == 401:
            raise AuthenticationError(
                "Invalid API key. Get a new one at https://poke.com/kitchen/api-keys",
                status=401,
            ) from e
        if status == 403:
            raise ForbiddenError(
                "API key doesn't have permission for this action",
                status=403,
            ) from e
        if status == 429:
            raise RateLimitError(
                "Rate limited. Please slow down and retry.",
                status=429,
            ) from e
        raise PokeError(
            f"Poke API error ({status}): {msg}",
            status=status,
        ) from e
    except URLError as e:
        raise PokeError(f"Network error: {e.reason}") from e


class Poke:
    """Poke SDK client.

    Args:
        api_key: API key. Falls back to ``POKE_API_KEY`` env var,
            then ``~/.config/poke/credentials.json``.
        base_url: API base URL. Falls back to ``POKE_API`` env var,
            then ``https://poke.com/api/v1``.
    """

    def __init__(
        self,
        *,
        api_key: Optional[str] = None,
        base_url: Optional[str] = None,
    ):
        self._api_key = _resolve_api_key(api_key)
        self._base_url = _resolve_base_url(base_url)

    def _headers(self, token: Optional[str] = None) -> Dict[str, str]:
        return {
            "Authorization": f"Bearer {token or self._api_key}",
            "Content-Type": "application/json",
            "User-Agent": f"poke-python/{__version__} ({platform.system()})",
        }

    def send_message(self, message: str) -> Dict[str, Any]:
        """Send a message to your Poke agent.

        Args:
            message: The text message to send.

        Returns:
            ``{"success": True, "message": "Message sent successfully"}``
        """
        return _request(
            f"{self._base_url}/inbound/api-message",
            headers=self._headers(),
            data={"message": message},
        )

    def create_webhook(
        self, *, condition: str, action: str
    ) -> Dict[str, Any]:
        """Create a webhook trigger.

        Args:
            condition: When this webhook should fire (e.g. "When a new order is placed").
            action: What the agent should do (e.g. "Send me a summary").

        Returns:
            ``{"triggerId": "...", "webhookUrl": "...", "webhookToken": "..."}``
        """
        return _request(
            f"{self._base_url}/api-keys/webhook",
            headers=self._headers(),
            data={"condition": condition, "action": action},
        )

    def send_webhook(
        self,
        *,
        webhook_url: str,
        webhook_token: str,
        data: Dict[str, Any],
    ) -> Dict[str, Any]:
        """Fire a webhook with a data payload.

        Uses the ``webhook_url`` and ``webhook_token`` returned by
        :meth:`create_webhook` — **not** the API key.

        Args:
            webhook_url: The webhook URL from ``create_webhook``.
            webhook_token: The webhook token from ``create_webhook``.
            data: Arbitrary JSON-serializable payload.

        Returns:
            ``{"success": True}``
        """
        return _request(
            webhook_url,
            headers=self._headers(token=webhook_token),
            data=data,
        )
