"""Resource modules — sessions + embed.

Kept in one file because the resource layer is genuinely thin (it
forwards to ``HttpClient`` and types the response). Splitting per
endpoint would be noise.
"""

from __future__ import annotations

from typing import Any, Dict, Optional, cast
from urllib.parse import quote

from ._http import HttpClient
from .types import (
    CreateSessionParams,
    EmbedBootstrapParams,
    EmbedBootstrapResponse,
    Session,
    SessionWithClientSecret,
)


class SessionsResource:
    """``POST /v1/gate_sessions`` and friends — the Stripe-Checkout-Session analog."""

    def __init__(self, http: HttpClient) -> None:
        self._http = http

    def create(
        self,
        params: CreateSessionParams,
        *,
        idempotency_key: Optional[str] = None,
        timeout: Optional[float] = None,
        max_retries: Optional[int] = None,
    ) -> SessionWithClientSecret:
        """Create a new ramp session.

        Returns the session plus ``client_secret`` — shown exactly
        once. Forward to the browser; subsequent reads via
        :meth:`retrieve` omit it.
        """
        return cast(
            SessionWithClientSecret,
            self._http.request(
                method="POST",
                path="/v1/gate_sessions",
                body=dict(params),
                idempotency_key=idempotency_key,
                timeout=timeout,
                max_retries=max_retries,
            ),
        )

    def retrieve(
        self,
        session_id: str,
        *,
        timeout: Optional[float] = None,
        max_retries: Optional[int] = None,
    ) -> Session:
        """Read a session by id. ``client_secret`` is NOT returned."""
        return cast(
            Session,
            self._http.request(
                method="GET",
                path=f"/v1/gate_sessions/{quote(session_id, safe='')}",
                timeout=timeout,
                max_retries=max_retries,
            ),
        )

    def cancel(
        self,
        session_id: str,
        *,
        idempotency_key: Optional[str] = None,
        timeout: Optional[float] = None,
        max_retries: Optional[int] = None,
    ) -> Session:
        """Cancel an ``open`` session.

        Raises :class:`gate.errors.IdempotencyError` (409) if the
        session is already in a terminal state — re-cancelling is
        intentionally an error, not a no-op, so partners notice
        double-cancel bugs.
        """
        return cast(
            Session,
            self._http.request(
                method="POST",
                path=f"/v1/gate_sessions/{quote(session_id, safe='')}/cancel",
                idempotency_key=idempotency_key,
                timeout=timeout,
                max_retries=max_retries,
            ),
        )


class EmbedResource:
    """``POST /v1/embed/bootstrap`` — gated by publishable key, not secret.

    Most partners won't call this server-side (the browser SDK does it).
    SSR partners pre-minting embed tokens before delivering HTML can.
    """

    def __init__(self, http: HttpClient) -> None:
        self._http = http

    def bootstrap(
        self,
        params: Optional[EmbedBootstrapParams] = None,
        *,
        idempotency_key: Optional[str] = None,
        timeout: Optional[float] = None,
        max_retries: Optional[int] = None,
    ) -> EmbedBootstrapResponse:
        body: Dict[str, Any] = dict(params) if params else {}
        return cast(
            EmbedBootstrapResponse,
            self._http.request(
                method="POST",
                path="/v1/embed/bootstrap",
                body=body,
                idempotency_key=idempotency_key,
                timeout=timeout,
                max_retries=max_retries,
            ),
        )


__all__ = ["SessionsResource", "EmbedResource"]
