#!/usr/bin/env python3
"""
Run a recipe: plan then execute.

This is a convenience wrapper that:
1. Generates a plan (runs analyzers, expands SLICE_ON)
2. Executes the plan (produces video output)
"""

import json
import sys
import tempfile
from pathlib import Path

# Add artdag to path
sys.path.insert(0, str(Path(__file__).parent.parent / "artdag"))

from artdag.sexp import compile_string
from artdag.sexp.planner import create_plan
from artdag.sexp.parser import Binding

# Import execute functionality
from execute import execute_plan


class PlanEncoder(json.JSONEncoder):
    """JSON encoder that handles Binding objects."""
    def default(self, obj):
        if isinstance(obj, Binding):
            return {
                "_bind": obj.analysis_ref,
                "range_min": obj.range_min,
                "range_max": obj.range_max,
            }
        return super().default(obj)


def run_recipe(recipe_path: Path, output_path: Path = None):
    """Run a recipe file: plan then execute."""

    recipe_text = recipe_path.read_text()
    recipe_dir = recipe_path.parent

    print(f"=== COMPILE ===")
    print(f"Recipe: {recipe_path}")
    compiled = compile_string(recipe_text)
    print(f"Name: {compiled.name} v{compiled.version}")
    print(f"Nodes: {len(compiled.nodes)}")

    # Track analysis results
    analysis_data = {}

    def on_analysis(node_id, results):
        analysis_data[node_id] = results
        times = results.get("times", [])
        print(f"  Analysis: {len(times)} beat times @ {results.get('tempo', 0):.1f} BPM")

    # Generate plan
    print(f"\n=== PLAN ===")
    plan = create_plan(
        compiled,
        inputs={},
        recipe_dir=recipe_dir,
        on_analysis=on_analysis,
    )

    print(f"Plan ID: {plan.plan_id[:16]}...")
    print(f"Steps: {len(plan.steps)}")

    # Write plan to temp file for execute
    plan_dict = {
        "plan_id": plan.plan_id,
        "recipe_id": compiled.name,
        "recipe_hash": plan.recipe_hash,
        "encoding": compiled.encoding,
        "output_step_id": plan.output_step_id,
        "steps": [],
    }

    for step in plan.steps:
        step_dict = {
            "step_id": step.step_id,
            "node_type": step.node_type,
            "config": step.config,
            "inputs": step.inputs,
            "level": step.level,
            "cache_id": step.cache_id,
        }
        if step.node_type == "ANALYZE" and step.step_id in analysis_data:
            step_dict["config"]["analysis_results"] = analysis_data[step.step_id]
        plan_dict["steps"].append(step_dict)

    # Save plan
    work_dir = Path(tempfile.mkdtemp(prefix="artdag_run_"))
    plan_file = work_dir / "plan.json"
    with open(plan_file, "w") as f:
        json.dump(plan_dict, f, indent=2, cls=PlanEncoder)

    print(f"Plan saved: {plan_file}")

    # Execute plan
    print(f"\n=== EXECUTE ===")
    result = execute_plan(plan_file, output_path, recipe_dir)

    print(f"\n=== DONE ===")
    print(f"Output: {result}")
    return result


if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: run.py <recipe.sexp> [output.mp4]")
        print()
        print("Commands:")
        print("  run.py <recipe>      - Plan and execute recipe")
        print("  plan.py <recipe>     - Generate plan only")
        print("  execute.py <plan>    - Execute pre-generated plan")
        sys.exit(1)

    recipe_path = Path(sys.argv[1])
    output_path = Path(sys.argv[2]) if len(sys.argv) > 2 else None

    if not recipe_path.exists():
        print(f"Recipe not found: {recipe_path}")
        sys.exit(1)

    run_recipe(recipe_path, output_path)
