"""
JSON passthrough parser — wraps JSON documents as structured elements.

Strategy:
- Emit a meta:document_title element with the file name
- If root is an object: recursively walk keys; nested dicts become section headers,
  leaf values become text:narrative with section_path breadcrumb
- If root is an array: emit each item (recursing into dicts)
- Scalar root: single text:narrative
"""

from __future__ import annotations

import json
from collections.abc import Iterator
from typing import Any

from .base import BaseParser, FileRecord, RawElement


def _describe(value: Any) -> str:
    """Serialize a scalar/list value to a human-readable string."""
    if isinstance(value, str):
        return value
    if isinstance(value, bool):
        return str(value).lower()
    if isinstance(value, (int, float)):
        return str(value)
    return json.dumps(value, indent=2, ensure_ascii=False)


def _walk_dict(
    data: dict,
    path: list[str],
    depth: int,
) -> Iterator[RawElement]:
    """Recursively walk a JSON object, yielding section headers and narratives."""
    for key, value in data.items():
        key_str = str(key)
        current_path = path + [key_str]
        section_path = " > ".join(current_path)

        if isinstance(value, dict) and value:
            # Nested object → emit as section header then recurse
            yield RawElement(
                element_type="structural:section_header",
                text=key_str,
                heading_level=min(depth + 2, 6),
                detection_tier=2,
                extra={
                    "extraction_method": "json:stdlib",
                    "confidence": 0.85,
                    "section_path_hint": section_path,
                },
            )
            yield from _walk_dict(value, current_path, depth + 1)
        elif isinstance(value, list):
            # Array value → emit section header + each item
            if any(isinstance(i, dict) for i in value):
                yield RawElement(
                    element_type="structural:section_header",
                    text=key_str,
                    heading_level=min(depth + 2, 6),
                    detection_tier=2,
                    extra={
                        "extraction_method": "json:stdlib",
                        "confidence": 0.85,
                        "section_path_hint": section_path,
                    },
                )
                for item in value:
                    if isinstance(item, dict):
                        yield from _walk_dict(item, current_path, depth + 1)
                    else:
                        text_val = _describe(item)
                        if text_val.strip():
                            yield RawElement(
                                element_type="list:item",
                                text=text_val,
                                extra={
                                    "extraction_method": "json:stdlib",
                                    "confidence": 0.85,
                                    "section_path_hint": section_path,
                                },
                            )
            else:
                # Array of scalars → comma-joined narrative
                items_text = ", ".join(_describe(i) for i in value if _describe(i).strip())
                if items_text:
                    yield RawElement(
                        element_type="text:narrative",
                        text=f"{key_str}: {items_text}",
                        extra={
                            "extraction_method": "json:stdlib",
                            "confidence": 0.88,
                            "section_path_hint": section_path,
                        },
                    )
        else:
            # Scalar leaf
            text_val = _describe(value)
            if text_val.strip():
                yield RawElement(
                    element_type="text:narrative",
                    text=f"{key_str}: {text_val}",
                    extra={
                        "extraction_method": "json:stdlib",
                        "confidence": 0.90,
                        "section_path_hint": section_path,
                    },
                )


class JSONParser(BaseParser):
    handles = [("application/json", None)]

    def parse(self, file_record: FileRecord) -> Iterator[RawElement]:
        try:
            text = file_record.path.read_text(encoding="utf-8", errors="replace")
            data = json.loads(text)
        except json.JSONDecodeError as e:
            yield RawElement(
                element_type="meta:extraction_error",
                text=f"JSON parse error: {e}",
                extra={"extraction_method": "json:stdlib", "confidence": 0.0},
            )
            return

        # Title element
        yield RawElement(
            element_type="meta:document_title",
            text=file_record.path.stem,
            extra={"extraction_method": "json:stdlib", "confidence": 1.0},
        )

        root_path = [file_record.path.stem]

        if isinstance(data, dict):
            yield from _walk_dict(data, root_path, depth=0)
        elif isinstance(data, list):
            for item in data:
                if isinstance(item, dict):
                    yield from _walk_dict(item, root_path, depth=0)
                else:
                    text_val = _describe(item)
                    if text_val.strip():
                        yield RawElement(
                            element_type="text:narrative",
                            text=text_val,
                            extra={"extraction_method": "json:stdlib", "confidence": 0.85},
                        )
        else:
            yield RawElement(
                element_type="text:narrative",
                text=_describe(data),
                extra={"extraction_method": "json:stdlib", "confidence": 0.85},
            )
