"""Load YAML configuration for TAP runs."""

import importlib.resources
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Callable, Dict, List, Optional

import yaml

from taprune.parsers import get_parser
from taprune.prompts import get_prompts


def load_config(path: str | Path) -> Dict[str, Any]:
    """Load a single YAML config file."""
    with open(path, "r") as f:
        return yaml.safe_load(f)


def load_named_config(name: str) -> Dict[str, Any]:
    """Load a bundled config by name (e.g. 'default', 'example_extras')."""
    ref = importlib.resources.files("taprune.configs").joinpath(f"{name}.yaml")
    if not ref.is_file():
        return {}
    return yaml.safe_load(ref.read_text(encoding="utf-8"))


@dataclass
class TapConfig:
    """
    Typed view over the raw config dict. Use from_dict(load_config(path)) then
    access .goal, .api, .models, .tap, .target_system_prompt, .target_chat_history,
    and .resolve_prompts().
    """

    goal: str
    api: Dict[str, Any]
    models: Dict[str, Any]
    tap: Dict[str, Any]
    target_system_prompt: Any  # str | None
    target_chat_history: List[dict]
    starting_string: Any  # str | None
    extra_parser: Optional[Callable[[str], Any]]  # from config extra_parser: "parse_deal_from_reply" etc.
    _raw: Dict[str, Any]

    @classmethod
    def from_dict(cls, d: Dict[str, Any]) -> "TapConfig":
        if d is None:
            d = {}
        api = d.get("api") or {}
        models = d.get("models") or {}
        tap = d.get("tap") or {}
        target_ctx = d.get("target_context") or {}
        goal = d.get("goal") or "Your attack goal here"
        starting_string = d.get("starting_string")
        extra_parser = get_parser(d.get("extra_parser"))
        return cls(
            goal=goal,
            api=api,
            models=models,
            tap=tap,
            target_system_prompt=target_ctx.get("system_prompt"),
            target_chat_history=target_ctx.get("chat_history") or [],
            starting_string=starting_string,
            extra_parser=extra_parser,
            _raw=d,
        )

    def resolve_prompts(self) -> Dict[str, str]:
        """Return judge, off_topic, attacker prompts with placeholders filled."""
        start = self.starting_string or ("Sure, here is " + self.goal[:50] + "...")
        return get_prompts(self._raw, self.goal, start)

    @property
    def raw(self) -> Dict[str, Any]:
        """Raw config dict (e.g. for save_result)."""
        return self._raw
