"""Helpers comuns a todos os resources.

Cada Resource recebe um `HTTPTransport` (sync) ou `AsyncHTTPTransport` (async)
no construtor e expõe métodos que correspondem 1-para-1 com endpoints da API.

Centralizamos aqui a coerção de input — qualquer método aceita tanto um
modelo Pydantic quanto um dict bruto, e nós convertemos via `model_validate`.
Isso mantém o uso ergonômico para quem prefere dicts e validado para quem
prefere modelos tipados.
"""

from __future__ import annotations

from collections.abc import Mapping
from typing import Any, TypeVar

from pydantic import BaseModel

from .._http import AsyncHTTPTransport, HTTPTransport

ModelT = TypeVar("ModelT", bound=BaseModel)


def coerce_params(params: BaseModel | Mapping[str, Any] | None, model: type[ModelT]) -> ModelT:
    """Aceita modelo, dict ou None e devolve uma instância validada de `model`.

    Útil para que cada resource permita ambos:

    >>> client.customers.create(CreateCustomerParams(email="a@b.com"))
    >>> client.customers.create({"email": "a@b.com"})

    Lança `pydantic.ValidationError` se o payload não bater com o schema.
    """
    if isinstance(params, model):
        return params
    if isinstance(params, BaseModel):
        return model.model_validate(params.model_dump(by_alias=True))
    if params is None:
        return model()
    return model.model_validate(params)


def list_payload(data: Any) -> list[Any]:
    """Normaliza respostas de listagem.

    Algumas listagens vêm como array direto, outras como `{"data": [...]}`
    (já desempacotado pelo transporte). Aqui só garantimos que o consumidor
    sempre recebe uma lista.
    """
    if isinstance(data, list):
        return list(data)
    if isinstance(data, dict):
        nested = data.get("data")
        if isinstance(nested, list):
            return list(nested)
        items = data.get("items")
        if isinstance(items, list):
            return list(items)
    return [data] if data is not None else []


class SyncResource:
    """Base de todos os resources síncronos."""

    def __init__(self, transport: HTTPTransport) -> None:
        self._transport = transport

    def _get(self, path: str, **kwargs: Any) -> Any:
        return self._transport.request("GET", path, **kwargs)

    def _post(self, path: str, **kwargs: Any) -> Any:
        return self._transport.request("POST", path, **kwargs)


class AsyncResource:
    """Base de todos os resources assíncronos."""

    def __init__(self, transport: AsyncHTTPTransport) -> None:
        self._transport = transport

    async def _get(self, path: str, **kwargs: Any) -> Any:
        return await self._transport.request("GET", path, **kwargs)

    async def _post(self, path: str, **kwargs: Any) -> Any:
        return await self._transport.request("POST", path, **kwargs)


def with_id_param(id_: str | None, extra: Mapping[str, Any] | None = None) -> dict[str, Any]:
    """Constrói o `params` para endpoints que esperam `?id=...` como querystring."""
    out: dict[str, Any] = {}
    if id_ is not None:
        out["id"] = id_
    if extra:
        out.update(extra)
    return out


__all__ = [
    "AsyncResource",
    "SyncResource",
    "coerce_params",
    "list_payload",
    "with_id_param",
]
