"""Planner configuration for {{ project_name }}."""

from __future__ import annotations

import json
from collections.abc import Mapping, Sequence
from dataclasses import dataclass
from typing import Any

from penguiflow.planner import PlannerEventCallback, ReactPlanner

from .config import Config
from .tools import build_catalog_bundle


@dataclass
class PlannerBundle:
    """Container for planner and LLM client."""

    planner: ReactPlanner
    llm_client: "ScriptedLLM"


class ScriptedLLM:
    """Deterministic LLM client that returns lighthouse planner actions."""

    def __init__(self, scripted: Sequence[Mapping[str, Any]] | None = None) -> None:
        self._scripted = [json.dumps(item, ensure_ascii=False) for item in scripted] if scripted else None

    async def complete(
        self,
        *,
        messages: list[Mapping[str, str]],
        response_format: Mapping[str, Any] | None = None,
        stream: bool = False,
        on_stream_chunk: object = None,
    ) -> str:
        del response_format, stream, on_stream_chunk
        if self._scripted is None:
            query = messages[-1].get("content", "")
            scripted = [
                {
                    "thought": "upload files",
                    "next_node": "upload_files",
                    "args": {"paths": ["./docs/policy.pdf"]},
                },
                {
                    "thought": "start ingest",
                    "next_node": "ingest_documents",
                    "args": {"file_ids": ["file-0"]},
                },
                {
                    "thought": "poll status",
                    "next_node": "check_ingest_status",
                    "args": {"job_id": "job-123", "status": "pending"},
                },
                {
                    "thought": "query index",
                    "next_node": "query_index",
                    "args": {"question": query},
                },
                {
                    "thought": "finish",
                    "next_node": None,
                    "args": None,
                },
            ]
            self._scripted = [json.dumps(item, ensure_ascii=False) for item in scripted]

        if not self._scripted:
            raise RuntimeError("ScriptedLLM has no responses left")

        return self._scripted.pop(0)


def build_planner(
    config: Config,
    *,
    event_callback: PlannerEventCallback | None = None,
) -> PlannerBundle:
    """Create a ReactPlanner wired with scripted responses.

    Swap the scripted client with a real model by:
    - LiteLLM path: pass llm=config.llm_model (e.g., "gpt-4o") to ReactPlanner and set provider keys in env
      (e.g., OPENAI_API_KEY).
    - DSPy path: pass llm_client=DSPyLLMClient(llm=config.llm_model) and leave llm=None.
    - Custom client: pass any object with .complete(messages=[...], response_format=...).
    Prompt tweaks: pass system_prompt_extra (string) or planning_hints (mapping) to ReactPlanner to append
    guidance without editing penguiflow.planner.prompts.
    """
    del config  # kept for future expansion
    nodes, registry = build_catalog_bundle()
    llm_client = ScriptedLLM()
    planner = ReactPlanner(
        llm_client=llm_client,
        nodes=nodes,
        registry=registry,
        event_callback=event_callback,
    )
    return PlannerBundle(planner=planner, llm_client=llm_client)
