from typing_extensions import NotRequired, TypedDict
from alchemy.core import Endpoint
from pydantic import TypeAdapter

class Address(TypedDict):
  address: str
  """Wallet address whose fungible tokens should be fetched."""
  networks: list[str]
  """Networks to query for this wallet address."""

class TokenMetadata(TypedDict):
  decimals: NotRequired[int | None]
  logo: NotRequired[str | None]
  name: NotRequired[str | None]
  symbol: NotRequired[str | None]

class TokenPrice(TypedDict):
  currency: str
  value: str
  lastUpdatedAt: str

class Request(TypedDict):
  addresses: list[Address]
  """Array of wallet addresses and the networks to query them on. The docs state a maximum of 2 addresses and 5 networks per address."""
  withMetadata: NotRequired[bool]
  """Whether to include token metadata such as symbol, name, logo, and decimals."""
  withPrices: NotRequired[bool]
  """Whether to include price snapshots for each returned token."""
  includeNativeTokens: NotRequired[bool]
  """Whether to include the native gas token balance for each requested network."""
  includeErc20Tokens: NotRequired[bool]
  """Whether to include ERC-20 token balances."""
  pageKey: NotRequired[str]
  """Pagination cursor returned by a previous response."""
  pageSize: NotRequired[int]
  """Maximum number of token records to return."""

class Token(TypedDict):
  address: str
  network: str
  tokenAddress: str | None
  tokenBalance: str
  tokenMetadata: NotRequired[TokenMetadata | None]
  tokenPrices: NotRequired[list[TokenPrice] | None]
  error: NotRequired[str | None]

class Data(TypedDict):
  tokens: list[Token]
  pageKey: str | None

class Response(TypedDict):
  data: Data

adapter = TypeAdapter(Response)

class Tokens(Endpoint):
  async def __call__(self, request: Request, *, validate: bool | None = None) -> Response:
    """Fetches fungible tokens for multiple wallet addresses and networks, optionally including metadata and prices.
    
    - `request`
    - `validate`: Whether to validate the response against the expected schema (default: client setting). (default: None)
    
    [Official docs](https://www.alchemy.com/docs/data/portfolio-apis/portfolio-api-endpoints/portfolio-api-endpoints/get-tokens-by-address)"""
    r = await self.request('POST', '/assets/tokens/by-address', json=request)
    
    if r.status_code != 200:
      self.raise_error(r)
    return adapter.validate_json(r.text) if self.should_validate(validate) else r.json()
