#!/usr/bin/env python3
"""Export canonical culinary recipes as clean Markdown knowledge documents."""

from __future__ import annotations

import argparse
import shutil
import tempfile
from pathlib import Path

import yaml


ROOT = Path(__file__).resolve().parent.parent
CULINARY_DIR = ROOT / "culinary"
DEFAULT_OUTPUT = ROOT / "generated/open-webui/recipes"


def load_entities(directory: Path) -> dict[str, dict]:
    entities = {}
    for path in sorted(directory.glob("*.yaml")):
        data = yaml.safe_load(path.read_text(encoding="utf-8"))
        entity_id = data["id"]
        if entity_id in entities:
            raise ValueError(f"duplicate ID {entity_id!r} in {directory}")
        entities[entity_id] = data
    return entities


def amount_text(amount: dict | None) -> str:
    if not amount:
        return "—"
    display = amount.get("display")
    if display:
        return display
    quantity = amount["quantity"]
    maximum = amount.get("quantity_max")
    value = f"{quantity:g}" if isinstance(quantity, float) else str(quantity)
    if maximum is not None:
        upper = f"{maximum:g}" if isinstance(maximum, float) else str(maximum)
        value = f"{value}–{upper}"
    return f"{value} {amount['unit_id'].replace('_', ' ')}"


def render_recipe(recipe: dict, ingredients: dict[str, dict], recipes: dict[str, dict]) -> str:
    lines = [f"# {recipe['title']}", ""]
    lines.extend(
        [
            f"Recipe ID: `{recipe['id']}`",
            f"Categories: {', '.join(recipe['categories']) or 'None'}",
            f"Tags: {', '.join(recipe['tags']) or 'None'}",
            f"Yield: {amount_text(recipe['yield']['amount'])}",
        ]
    )
    if recipe["yield"].get("servings") is not None:
        lines.append(f"Servings: {recipe['yield']['servings']:g}")
    if recipe["yield"].get("description"):
        lines.append(f"Yield description: {recipe['yield']['description']}")
    lines.append("")

    for component in recipe["components"]:
        lines.extend([f"## {component['name']}", "", "| Item | Amount | Formula percentage |", "| --- | ---: | ---: |"])
        for item in component["items"]:
            reference = item["reference"]
            if "ingredient_id" in reference:
                item_id = reference["ingredient_id"]
                label = ingredients[item_id]["name"]
            else:
                item_id = reference["recipe_id"]
                label = f"{recipes[item_id]['title']} (sub-recipe)"
            percentage = f"{item['percentage']:g}%" if "percentage" in item else "—"
            lines.append(f"| {label} | {amount_text(item['amount'])} | {percentage} |")
        if component.get("notes"):
            lines.extend(["", *[f"- {note}" for note in component["notes"]]])
        lines.append("")

    lines.extend(["## Preparation", ""])
    for step in sorted(recipe["steps"], key=lambda value: value["order"]):
        lines.append(f"{step['order']}. {step['instruction']}")
    if recipe.get("notes"):
        lines.extend(["", "## Notes", "", *[f"- {note}" for note in recipe["notes"]]])
    return "\n".join(lines).rstrip() + "\n"


def parse_args():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("output", nargs="?", type=Path, default=DEFAULT_OUTPUT)
    return parser.parse_args()


def main() -> int:
    args = parse_args()
    output = args.output.resolve()
    if output in {Path("/"), ROOT}:
        raise ValueError(f"refusing unsafe output directory: {output}")
    ingredients = load_entities(CULINARY_DIR / "ingredients")
    recipes = load_entities(CULINARY_DIR / "recipes")
    output.parent.mkdir(parents=True, exist_ok=True)
    staging = Path(tempfile.mkdtemp(prefix="recipe-corpus-", dir=output.parent))
    try:
        for recipe_id, recipe in recipes.items():
            (staging / f"{recipe_id}.md").write_text(
                render_recipe(recipe, ingredients, recipes), encoding="utf-8"
            )
        if output.exists():
            shutil.rmtree(output)
        staging.replace(output)
    except Exception:
        shutil.rmtree(staging, ignore_errors=True)
        raise
    print(f"Exported {len(recipes)} canonical recipes to {output}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
