"""Source map utilities for mapping JSON pointers to line numbers."""

import json_source_map  # type: ignore[import-untyped]


def build_source_map(raw_text: str) -> dict[str, int] | None:
    """Build a JSON pointer → line number mapping from raw JSON text."""
    try:
        result = json_source_map.calculate(raw_text)
        line_map: dict[str, int] = {}
        for pointer, entry in result.items():
            pos = entry.value_start
            line_map[pointer] = pos.line + 1
        return line_map
    except Exception:
        return None


def lookup_line(source_map: dict[str, int] | None, json_pointer: str) -> int | None:
    """Look up a line number from a source map by JSON pointer.

    If the exact pointer is not found, walks up parent pointers until a match
    is found. This handles "absence" rules that point to keys that don't exist
    in the JSON (e.g. /nodes/2/credentials when credentials is missing).
    """
    if source_map is None:
        return None
    line = source_map.get(json_pointer)
    if line is not None:
        return line
    # Walk up parent pointers
    pointer = json_pointer
    while "/" in pointer:
        pointer = pointer.rsplit("/", 1)[0]
        line = source_map.get(pointer)
        if line is not None:
            return line
    # Try root (empty string = root in RFC 6901)
    return source_map.get("")
