"""Payload serialization for Stacks transactions.

Implements TokenTransfer and ContractCall payload types per SIP-005.
"""

from __future__ import annotations

from .c32 import c32_address_decode
from .constants import (
    PAYLOAD_TYPE_TOKEN_TRANSFER,
    PAYLOAD_TYPE_CONTRACT_CALL,
    MEMO_MAX_LENGTH,
    PRINCIPAL_TYPE_STANDARD,
)


def _serialize_standard_principal_for_payload(address: str) -> bytes:
    """Serialize a standard principal for use in payloads.

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


def serialize_token_transfer_payload(
    recipient: str,
    amount: int,
    memo: str = "",
) -> bytes:
    """Serialize a token transfer payload.

    Format: payload_type(1) + principal(22) + amount(8 BE) + memo(34 padded)
    """
    # Payload type
    result = bytes([PAYLOAD_TYPE_TOKEN_TRANSFER])

    # Recipient principal
    result += _serialize_standard_principal_for_payload(recipient)

    # Amount (8 bytes, big-endian)
    result += amount.to_bytes(8, "big")

    # Memo: 34 bytes zero-padded (no type prefix per SIP-005)
    memo_bytes = memo.encode("utf-8")[:MEMO_MAX_LENGTH]
    padded_memo = memo_bytes.ljust(MEMO_MAX_LENGTH, b"\x00")
    result += padded_memo

    return result


def serialize_contract_call_payload(
    contract_address: str,
    contract_name: str,
    function_name: str,
    function_args: list[bytes],
) -> bytes:
    """Serialize a contract call payload.

    Format: payload_type(1) + address(22) + contract_name_len(1) + contract_name
            + function_name_len(1) + function_name + num_args(4 BE) + args...
    """
    # Payload type
    result = bytes([PAYLOAD_TYPE_CONTRACT_CALL])

    # Contract address (standard principal without type prefix)
    version, hash160_bytes = c32_address_decode(contract_address)
    result += bytes([version]) + hash160_bytes

    # Contract name (length-prefixed)
    name_bytes = contract_name.encode("ascii")
    result += bytes([len(name_bytes)]) + name_bytes

    # Function name (length-prefixed)
    fn_bytes = function_name.encode("ascii")
    result += bytes([len(fn_bytes)]) + fn_bytes

    # Function arguments (4-byte count + concatenated args)
    result += len(function_args).to_bytes(4, "big")
    for arg in function_args:
        result += arg

    return result
