from __future__ import annotations

"""Outline / summary recipe built on top of semantic graph nodes.

This recipe is deterministic and does not call an external LLM. It
materialises an outline-style dataset using SUMMARY and SECTION nodes from
:class:`DocumentGraph`.
"""

from pathlib import Path
import json

from ..core.models import DatasetRecipe, DocumentGraph, NodeType
from ..llm import LLMClient, build_llm_from_recipe_params


def _ensure_recipe(recipe: DatasetRecipe | None) -> DatasetRecipe:
    if recipe is not None:
        return recipe
    return DatasetRecipe(
        name="outline_summary",
        description="Default outline/summary recipe from section summaries.",
        input_query="",
        prompt_template="",
        output_schema={
            "section_title": "str",
            "summary": "str",
            "level": "int",
        },
    )


def run_outline_summary(
    recipe: DatasetRecipe | None,
    graph: DocumentGraph,
    base_dir: str | Path,
    document_id: str,
) -> Path:
    """Generate outline-style summaries from SUMMARY + SECTION nodes.

    Each record corresponds to one SUMMARY node and contains the section
    title, the summary text and the section level (if available).
    """

    recipe = _ensure_recipe(recipe)

    llm: LLMClient | None = build_llm_from_recipe_params(getattr(recipe, "params", None))

    base = Path(base_dir)
    ds_dir = base / "datasets" / recipe.name
    ds_dir.mkdir(parents=True, exist_ok=True)
    out_path = ds_dir / f"{document_id}.jsonl"

    # Build quick lookups
    section_by_id = {n.id: n for n in graph.nodes if n.node_type is NodeType.SECTION}
    summary_nodes = [n for n in graph.nodes if n.node_type is NodeType.SUMMARY]

    with out_path.open("w", encoding="utf-8") as f:
        for summary in summary_nodes:
            section_id = summary.metadata.get("source_section") if summary.metadata else None
            section = section_by_id.get(section_id)
            if not section:
                continue

            section_title = (section.label or "").strip() or None
            level = int(section.metadata.get("level", 1)) if section.metadata else 1

            base_summary_text = (summary.label or "").strip()
            if not base_summary_text:
                continue

            if llm is None:
                final_summary = base_summary_text
            else:
                # Let the LLM refine or rephrase the deterministic section summary.
                final_summary = llm.generate(base_summary_text)

            record = {
                "document_id": document_id,
                "section_id": section.id,
                "section_title": section_title,
                "summary": final_summary,
                "level": level,
                "metadata": {
                    **(graph.metadata or {}),
                    **(section.metadata or {}),
                },
            }
            f.write(json.dumps(record, ensure_ascii=False) + "\n")

    return out_path

