"""Clarity value serialization for Stacks transactions.

Implements the minimum set of Clarity values needed for SIP-010 token transfers:
  transfer(amount uint, sender principal, recipient principal, memo (optional (buff 34)))
"""

from __future__ import annotations

from .c32 import c32_address_decode
from .constants import (
    CLARITY_TYPE_UINT,
    CLARITY_TYPE_BUFFER,
    CLARITY_TYPE_STANDARD_PRINCIPAL,
    CLARITY_TYPE_CONTRACT_PRINCIPAL,
    CLARITY_TYPE_OPTIONAL_NONE,
    CLARITY_TYPE_OPTIONAL_SOME,
)


def serialize_uint(value: int) -> bytes:
    """Serialize a Clarity uint value.

    Format: type_id(1) + value(16 big-endian)
    """
    return bytes([CLARITY_TYPE_UINT]) + value.to_bytes(16, "big")


def serialize_standard_principal(address: str) -> bytes:
    """Serialize a Clarity standard principal value.

    Format: type_id(1) + version(1) + hash160(20)
    """
    version, hash160_bytes = c32_address_decode(address)
    return bytes([CLARITY_TYPE_STANDARD_PRINCIPAL, version]) + hash160_bytes


def serialize_contract_principal(address: str, contract_name: str) -> bytes:
    """Serialize a Clarity contract principal value.

    Format: type_id(1) + version(1) + hash160(20) + name_len(1) + name(n)
    """
    version, hash160_bytes = c32_address_decode(address)
    name_bytes = contract_name.encode("ascii")
    return (
        bytes([CLARITY_TYPE_CONTRACT_PRINCIPAL, version])
        + hash160_bytes
        + bytes([len(name_bytes)])
        + name_bytes
    )


def serialize_optional_none() -> bytes:
    """Serialize Clarity (none)."""
    return bytes([CLARITY_TYPE_OPTIONAL_NONE])


def serialize_optional_some(inner: bytes) -> bytes:
    """Serialize Clarity (some <inner>)."""
    return bytes([CLARITY_TYPE_OPTIONAL_SOME]) + inner


def serialize_buffer(data: bytes) -> bytes:
    """Serialize a Clarity buffer value.

    Format: type_id(1) + length(4 big-endian) + data
    """
    return bytes([CLARITY_TYPE_BUFFER]) + len(data).to_bytes(4, "big") + data


def serialize_buffer_from_string(text: str) -> bytes:
    """Serialize a UTF-8 string as a Clarity buffer."""
    return serialize_buffer(text.encode("utf-8"))
