"""Philips private tag resolution helpers."""

from typing import Any, Dict, List, Optional

import pydicom


def _resolve_philips_private_tag(
    ds: pydicom.Dataset,
    dd_number: int,
    element_offset: int,
    private_group: int = 0x2005,
) -> tuple[Optional[tuple[int, int]], Optional[str], Optional[str]]:
    """Resolve a Philips private tag by DD number and element offset.

    Philips stores private data using Private Creator tags that reserve
    256-element blocks within a private group. Each Private Creator tag
    at (group, 00xx) contains a string like "Philips MR Imaging DD 001".
    The block number is the last byte of the Private Creator tag address.

    To find a specific private element:
      1. Scan Private Creator tags (group, 0x0010)-(group, 0x00FF) for the
         DD string matching the requested dd_number.
      2. Take the block byte (last byte of the Private Creator tag address).
      3. Construct the resolved tag: (group, block_byte << 8 | element_offset).

    IMPORTANT: Block assignments are NOT fixed across scanners or software
    versions. They must be looked up dynamically per file.

    Args:
        ds: A pydicom Dataset (already read).
        dd_number: The DD number to look for (e.g. 1 for "DD 001").
        element_offset: The element offset within the DD block (e.g. 0x85).
        private_group: The DICOM private group to search (default 0x2005).

    Returns:
        Tuple of (resolved_tag, creator_string, value_str):
        - resolved_tag: (group, element) tuple, or None if not found.
        - creator_string: The Private Creator string that matched, or None.
        - value_str: String representation of the tag value, or None.
    """
    # Format the DD number for matching (e.g. 1 -> "001", 5 -> "005")
    dd_suffix = f"{dd_number:03d}"
    target_pattern = f"dd {dd_suffix}"

    # Scan Private Creator slots: (group, 0x0010) through (group, 0x00FF)
    for slot in range(0x0010, 0x0100):
        creator_tag = (private_group, slot)
        creator_elem = ds.get(creator_tag)
        if creator_elem is None:
            continue

        creator_str = str(creator_elem.value).strip()
        if not creator_str:
            continue

        # Check if this creator string matches our DD number
        if target_pattern in creator_str.lower():
            # The block byte is the slot number (last byte of creator tag)
            block_byte = slot
            resolved_element = (block_byte << 8) | element_offset
            resolved_tag = (private_group, resolved_element)

            # Try to read the value at the resolved tag
            value_elem = ds.get(resolved_tag)
            if value_elem is not None:
                value_str = str(value_elem.value)
            else:
                value_str = None

            return resolved_tag, creator_str, value_str

    return None, None, None


def _list_philips_private_creators(
    ds: pydicom.Dataset,
    private_group: int = 0x2005,
) -> List[Dict[str, Any]]:
    """List all Philips Private Creator tags in a dataset.

    Scans Private Creator slots (group, 0x0010)-(group, 0x00FF) and returns
    information about each occupied slot, including the DD string and block byte.

    Args:
        ds: A pydicom Dataset (already read).
        private_group: The DICOM private group to scan (default 0x2005).

    Returns:
        List of dicts with keys: slot, tag, block_byte, creator_string, dd_number.
    """
    creators = []
    for slot in range(0x0010, 0x0100):
        creator_tag = (private_group, slot)
        creator_elem = ds.get(creator_tag)
        if creator_elem is None:
            continue

        creator_str = str(creator_elem.value).strip()
        if not creator_str:
            continue

        # Try to extract DD number
        dd_number = None
        lower = creator_str.lower()
        dd_idx = lower.find("dd ")
        if dd_idx >= 0:
            dd_part = lower[dd_idx + 3 :].strip()
            # Extract leading digits
            digits = ""
            for ch in dd_part:
                if ch.isdigit():
                    digits += ch
                else:
                    break
            if digits:
                dd_number = int(digits)

        creators.append(
            {
                "slot": slot,
                "tag": f"({private_group:04X},{slot:04X})",
                "block_byte": f"0x{slot:02X}",
                "creator_string": creator_str,
                "dd_number": dd_number,
            }
        )

    return creators
