"""DICOM tree-building helpers for hierarchical structure display."""

from typing import Any, Dict, List

import pydicom
from pydicom.dataelem import DataElement

from dicom_mcp.pii import redact_if_pii


def _format_tree_value(elem: DataElement, max_value_len: int = 80) -> str:
    """Format a DataElement value for tree display.

    Truncates long values, handles bytes, multivalue, and sequences.
    """
    if elem.VR == "SQ":
        count = len(elem.value) if elem.value else 0
        return f"<Sequence: {count} item{'s' if count != 1 else ''}>"

    if elem.tag == (0x7FE0, 0x0010):
        return "<Pixel Data>"

    try:
        val = elem.value
    except Exception:
        return "<unreadable>"

    if isinstance(val, bytes):
        if len(val) > 32:
            return f"<{len(val)} bytes>"
        return repr(val)

    val_str = str(val)
    if len(val_str) > max_value_len:
        return val_str[:max_value_len] + "..."
    return val_str


def _build_tree_text(
    dataset: pydicom.Dataset,
    max_depth: int = 10,
    show_private: bool = True,
    depth: int = 0,
    prefix: str = "",
    is_last: bool = True,
) -> List[str]:
    """Build an indented text tree of a DICOM dataset.

    Returns a list of formatted strings with tree characters.
    """
    lines: List[str] = []
    elements = [elem for elem in dataset if elem.tag != (0x7FE0, 0x0010)]

    if not show_private:
        elements = [elem for elem in elements if not elem.tag.is_private]

    for i, elem in enumerate(elements):
        is_last_elem = i == len(elements) - 1
        tag_str = f"({elem.tag.group:04X},{elem.tag.element:04X})"
        keyword = elem.keyword or "Unknown"
        vr = elem.VR if hasattr(elem, "VR") else "??"

        # Apply PII redaction
        tag_tuple = (elem.tag.group, elem.tag.element)
        value_str = _format_tree_value(elem)
        redacted = redact_if_pii(tag_tuple, value_str)
        if redacted != value_str:
            value_str = str(redacted)

        if depth == 0:
            connector = ""
            child_prefix = ""
        else:
            connector = "└─ " if is_last_elem else "├─ "
            child_prefix = prefix + ("   " if is_last_elem else "│  ")

        line = f"{prefix}{connector}{tag_str} {keyword} [{vr}]: {value_str}"
        lines.append(line)

        # Recurse into sequences if within depth limit
        if elem.VR == "SQ" and elem.value and depth < max_depth:
            seq_items = list(elem.value)
            for seq_idx, item in enumerate(seq_items):
                is_last_item = seq_idx == len(seq_items) - 1

                if depth == 0:
                    item_connector = "└─ " if is_last_item and is_last_elem else "├─ "
                    item_child_prefix = (
                        "   " if is_last_item and is_last_elem else "│  "
                    )
                else:
                    item_connector = (
                        child_prefix + "└─ " if is_last_item else child_prefix + "├─ "
                    )
                    item_child_prefix = child_prefix + (
                        "   " if is_last_item else "│  "
                    )

                lines.append(f"{item_connector}Item {seq_idx + 1}")
                sub_lines = _build_tree_text(
                    item,
                    max_depth=max_depth,
                    show_private=show_private,
                    depth=depth + 1,
                    prefix=item_child_prefix,
                    is_last=is_last_item,
                )
                lines.extend(sub_lines)

    return lines


def _build_tree_json(
    dataset: pydicom.Dataset,
    max_depth: int = 10,
    show_private: bool = True,
    depth: int = 0,
) -> List[Dict[str, Any]]:
    """Build a JSON-serializable tree of a DICOM dataset.

    Returns a list of dicts, each with tag, vr, keyword, value, and
    optionally items (for sequences).
    """
    nodes: List[Dict[str, Any]] = []
    elements = [elem for elem in dataset if elem.tag != (0x7FE0, 0x0010)]

    if not show_private:
        elements = [elem for elem in elements if not elem.tag.is_private]

    for elem in elements:
        tag_str = f"({elem.tag.group:04X},{elem.tag.element:04X})"
        keyword = elem.keyword or "Unknown"
        vr = elem.VR if hasattr(elem, "VR") else "??"

        tag_tuple = (elem.tag.group, elem.tag.element)
        value_str = _format_tree_value(elem)
        redacted = redact_if_pii(tag_tuple, value_str)
        if redacted != value_str:
            value_str = str(redacted)

        node: Dict[str, Any] = {
            "tag": tag_str,
            "vr": vr,
            "keyword": keyword,
            "value": value_str,
        }

        if elem.VR == "SQ" and elem.value and depth < max_depth:
            items = []
            for seq_idx, item in enumerate(elem.value):
                children = _build_tree_json(
                    item,
                    max_depth=max_depth,
                    show_private=show_private,
                    depth=depth + 1,
                )
                items.append({"index": seq_idx + 1, "children": children})
            node["items"] = items

        nodes.append(node)

    return nodes
