"""Generate ``docProps/custom.xml`` for OOXML templates.

Custom properties embed compliance metadata (classification, watermark),
a SHA-256 hash of the resolved token inputs (for change detection), and
the template version — all as standard OOXML custom document properties.
"""

from __future__ import annotations

import hashlib
import json
from typing import Any

from lxml import etree

_CUSTOM_NS = "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties"
_VT_NS = "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"
_FMTID = "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"

_NSMAP = {
    None: _CUSTOM_NS,
    "vt": _VT_NS,
}


def build_custom_properties_xml(
    *,
    classification: str | None = None,
    template_hash: str | None = None,
    template_version: str | None = None,
    company: str | None = None,
) -> bytes:
    """Build ``docProps/custom.xml`` content.

    Args:
        classification: Document classification (e.g. "Confidential", "Internal").
        template_hash: SHA-256 hex digest of resolved token inputs.
        template_version: Semantic version of the template.
        company: Company name for metadata.

    Returns:
        UTF-8 encoded XML bytes.
    """
    root = etree.Element(f"{{{_CUSTOM_NS}}}Properties", nsmap=_NSMAP)

    pid = 2  # OOXML custom property IDs start at 2
    props: list[tuple[str, str]] = []
    if classification is not None:
        props.append(("Classification", classification))
    if template_hash is not None:
        props.append(("TemplateHash", template_hash))
    if template_version is not None:
        props.append(("TemplateVersion", template_version))
    if company is not None:
        props.append(("Company", company))

    for name, value in props:
        prop = etree.SubElement(root, f"{{{_CUSTOM_NS}}}property")
        prop.set("fmtid", _FMTID)
        prop.set("pid", str(pid))
        prop.set("name", name)
        vt = etree.SubElement(prop, f"{{{_VT_NS}}}lpwstr")
        vt.text = value
        pid += 1

    return etree.tostring(root, xml_declaration=True, encoding="UTF-8", standalone=True)


def compute_template_hash(inputs: dict[str, Any]) -> str:
    """Compute SHA-256 hash of resolved token inputs.

    Keys are sorted recursively for deterministic output regardless of
    dict insertion order.

    Args:
        inputs: Resolved input token values.

    Returns:
        Lowercase hex digest (64 characters).
    """
    canonical = json.dumps(inputs, sort_keys=True, separators=(",", ":"))
    return hashlib.sha256(canonical.encode("utf-8")).hexdigest()
