"""Official Python SDK for EmailAgent."""

from __future__ import annotations

from dataclasses import dataclass
from typing import Any
from urllib.parse import quote

import requests


@dataclass
class EmailAgentApiError(Exception):
    status_code: int
    payload: Any

    def __str__(self) -> str:
        if isinstance(self.payload, dict) and self.payload.get("error"):
            return str(self.payload["error"])
        return f"EmailAgent API error ({self.status_code})"


class EmailAgentClient:
    def __init__(self, api_key: str, base_url: str = "https://api.emailagent.dev") -> None:
        self.base_url = base_url.rstrip("/")
        self.session = requests.Session()
        self.session.headers.update({"Authorization": f"Bearer {api_key}"})

    def _request(
        self,
        method: str,
        path: str,
        body: dict[str, Any] | None = None,
        idempotency_key: str | None = None,
    ) -> Any:
        headers: dict[str, str] = {}
        if idempotency_key:
            headers["Idempotency-Key"] = idempotency_key

        response = self.session.request(
            method=method,
            url=f"{self.base_url}{path}",
            json=body,
            headers=headers or None,
            timeout=30,
        )

        payload: Any
        try:
            payload = response.json()
        except ValueError:
            payload = response.text

        if response.status_code >= 400:
            raise EmailAgentApiError(response.status_code, payload)

        return payload

    def list_inboxes(self) -> Any:
        return self._request("GET", "/api/v1/inboxes")

    def create_inbox(
        self,
        local_part: str,
        display_name: str | None = None,
        domain_name: str | None = None,
        idempotency_key: str | None = None,
    ) -> Any:
        body: dict[str, Any] = {"localPart": local_part}
        if display_name is not None:
            body["displayName"] = display_name
        if domain_name is not None:
            body["domainName"] = domain_name
        return self._request("POST", "/api/v1/inboxes", body, idempotency_key)

    def update_inbox(self, inbox_id: str, display_name: str, idempotency_key: str | None = None) -> Any:
        return self._request(
            "PATCH",
            f"/api/v1/inboxes/{inbox_id}",
            {"displayName": display_name},
            idempotency_key,
        )

    def delete_inbox(self, inbox_id: str, idempotency_key: str | None = None) -> Any:
        return self._request("DELETE", f"/api/v1/inboxes/{inbox_id}", None, idempotency_key)

    def send_email(
        self,
        inbox_id: str,
        to: str,
        subject: str | None = None,
        text: str | None = None,
        idempotency_key: str | None = None,
    ) -> Any:
        body: dict[str, Any] = {"inboxId": inbox_id, "to": to}
        if subject is not None:
            body["subject"] = subject
        if text is not None:
            body["text"] = text
        return self._request("POST", "/api/v1/emails/send", body, idempotency_key)

    def list_emails(self, inbox_id: str | None = None) -> Any:
        path = "/api/v1/emails"
        if inbox_id:
            path = f"{path}?inboxId={quote(inbox_id, safe='')}"
        return self._request("GET", path)

    def update_email_read(
        self,
        email_id: str,
        is_read: bool,
        idempotency_key: str | None = None,
    ) -> Any:
        return self._request(
            "PATCH",
            f"/api/v1/emails/{email_id}/read",
            {"isRead": is_read},
            idempotency_key,
        )

    def delete_email(self, email_id: str, idempotency_key: str | None = None) -> Any:
        return self._request("DELETE", f"/api/v1/emails/{email_id}", None, idempotency_key)

    def list_domains(self) -> Any:
        return self._request("GET", "/api/v1/domains")

    def create_domain(self, name: str, idempotency_key: str | None = None) -> Any:
        return self._request("POST", "/api/v1/domains", {"name": name}, idempotency_key)

    def verify_domain(self, domain_id: str, idempotency_key: str | None = None) -> Any:
        return self._request("POST", f"/api/v1/domains/{domain_id}/verify", None, idempotency_key)

    def delete_domain(self, domain_id: str, idempotency_key: str | None = None) -> Any:
        return self._request("DELETE", f"/api/v1/domains/{domain_id}", None, idempotency_key)

    def list_api_keys(self) -> Any:
        return self._request("GET", "/api/v1/api-keys")

    def create_api_key(
        self,
        name: str,
        scopes: list[str] | str | None = None,
        idempotency_key: str | None = None,
    ) -> Any:
        body: dict[str, Any] = {"name": name}
        if scopes is not None:
            body["scopes"] = scopes
        return self._request("POST", "/api/v1/api-keys", body, idempotency_key)

    def rotate_api_key(self, api_key_id: str, idempotency_key: str | None = None) -> Any:
        return self._request("POST", f"/api/v1/api-keys/{api_key_id}/rotate", None, idempotency_key)

    def revoke_api_key(self, api_key_id: str, idempotency_key: str | None = None) -> Any:
        return self._request("POST", f"/api/v1/api-keys/{api_key_id}/revoke", None, idempotency_key)

    def get_metrics(self) -> Any:
        return self._request("GET", "/api/v1/metrics")
