"""compute.py compute derived/size fields for every message type in axml.proto.

Each function updates the proto message *in place* so that all size, count, and
offset fields reflect the actual content.  All computation is performed in Rust;
Python is a thin serialization wrapper.

Typical usage::

    from pyaxml.proto import axml_pb2
    from pyaxml import compute

    sbs = axml.to_proto().stringblocks
    sbs.stringblocks[3].data = "new_value".encode()
    compute.string_blocks(sbs)
    # … then reconstruct: AXML.from_proto(proto)
"""

from __future__ import annotations

from pyaxml._pyaxml import (
    compute_string_block_proto as _rs_string_block,
    compute_string_blocks_proto as _rs_string_blocks,
    compute_resource_map_proto as _rs_resource_map,
    compute_xml_element_proto as _rs_xml_element,
    compute_arsc_res_table_config_proto as _rs_arsc_config,
    compute_arsc_res_type_proto as _rs_arsc_res_type,
    compute_arsc_res_table_package_proto as _rs_arsc_pkg,
    compute_axml_proto_bytes as _rs_axml,
    compute_arsc_proto_bytes as _rs_arsc,
)
from pyaxml.proto import axml_pb2


def string_block(block: "axml_pb2.StringBlock", is_utf8: bool) -> None:  # type: ignore[name-defined]
    """Compute ``size`` and ``redundant_size`` of a single StringBlock entry."""
    updated = _rs_string_block(block.SerializeToString(), is_utf8)
    block.ParseFromString(updated)


def string_blocks(sbs: "axml_pb2.StringBlocks", recursive: bool = True) -> None:  # type: ignore[name-defined]
    """Compute all derived fields of a StringBlocks (string pool) message."""
    updated = _rs_string_blocks(sbs.SerializeToString(), recursive)
    sbs.ParseFromString(updated)


def resource_map(rm: "axml_pb2.ResourceMap") -> None:  # type: ignore[name-defined]
    """Compute ``header.size`` from the number of resource IDs."""
    updated = _rs_resource_map(rm.SerializeToString())
    rm.ParseFromString(updated)


def xml_element(elt: "axml_pb2.XMLElement") -> None:  # type: ignore[name-defined]
    """Compute ``header.size`` (and ``start_elt.len_attributes``) for an XML element."""
    updated = _rs_xml_element(elt.SerializeToString())
    elt.ParseFromString(updated)


def arsc_res_table_config(cfg: "axml_pb2.ARSCResTableConfig") -> None:  # type: ignore[name-defined]
    """Compute ``size`` of an ARSCResTableConfig from present optional fields."""
    updated = _rs_arsc_config(cfg.SerializeToString())
    cfg.ParseFromString(updated)


def arsc_res_type(restype: "axml_pb2.ARSCResType", recursive: bool = True) -> None:  # type: ignore[name-defined]
    """Compute derived fields for an ARSCResType (TypeSpec or TypeType)."""
    updated = _rs_arsc_res_type(restype.SerializeToString(), recursive)
    restype.ParseFromString(updated)


def arsc_res_table_package(
    pkg: "axml_pb2.AXMLResTablePackage",  # type: ignore[name-defined]
    recursive: bool = True,
) -> None:
    """Compute all derived fields for a resource-table package."""
    updated = _rs_arsc_pkg(pkg.SerializeToString(), recursive)
    pkg.ParseFromString(updated)


def axml(axml_proto: "axml_pb2.AXML", recursive: bool = True) -> None:  # type: ignore[name-defined]
    """Compute all derived size/count fields in an AXML proto message."""
    updated = _rs_axml(axml_proto.SerializeToString(), recursive)
    axml_proto.ParseFromString(updated)


def arsc(arsc_proto: "axml_pb2.ARSC", recursive: bool = True) -> None:  # type: ignore[name-defined]
    """Compute all derived size/count fields in an ARSC proto message."""
    updated = _rs_arsc(arsc_proto.SerializeToString(), recursive)
    arsc_proto.ParseFromString(updated)
