"""Prompt template loading and rendering."""

from __future__ import annotations

import re
import warnings
from importlib.resources import files
from pathlib import Path

from abreka.errors import PromptTemplateError


def get_default_template(name: str) -> str:
    """Load a default prompt template shipped with the package.

    name should be one of: propose, implement, test, evaluate.
    """
    resource = files("abreka.defaults.prompts") / f"{name}.md"
    try:
        return resource.read_text(encoding="utf-8")
    except FileNotFoundError:
        raise PromptTemplateError(f"Default template not found: {name}.md")


_LEGACY_PROMPT_NAMES = {
    "propose_exploit": "propose",
}


def load_template(abreka_dir: Path, name: str) -> str:
    """Load a prompt template from the project's abreka/prompts/ directory.

    Falls back to the default template if the project-specific one doesn't exist.
    For backward compatibility, checks legacy names (e.g. propose.md → propose_exploit.md).
    """
    template_path = abreka_dir / "prompts" / f"{name}.md"
    if template_path.is_file():
        return template_path.read_text()

    # Check for legacy name (propose.md → propose_exploit.md)
    legacy_name = _LEGACY_PROMPT_NAMES.get(name)
    if legacy_name:
        legacy_path = abreka_dir / "prompts" / f"{legacy_name}.md"
        if legacy_path.is_file():
            warnings.warn(
                f"Prompt '{legacy_name}.md' has been renamed to '{name}.md'. "
                f"Please rename your file.",
                DeprecationWarning,
                stacklevel=2,
            )
            return legacy_path.read_text()

    return get_default_template(name)


def render_template(template: str, variables: dict[str, str]) -> str:
    """Substitute {{variable}} placeholders in a template string.

    Warns (but does not error) on missing variables.
    """
    def replacer(match: re.Match) -> str:
        var_name = match.group(1).strip()
        if var_name in variables:
            return variables[var_name]
        warnings.warn(f"Template variable {{{{{var_name}}}}} not found", stacklevel=2)
        return match.group(0)  # Leave the placeholder as-is

    return re.sub(r"\{\{(\s*\w+\s*)\}\}", replacer, template)


def format_guidance(text: str) -> str:
    """Wrap non-empty guidance text in a markdown section header."""
    text = text.strip()
    if not text:
        return ""
    return f"## Researcher Guidance\n\n{text}"


def format_wiki_index(index: dict) -> str:
    """Render the wiki index as a markdown section for the prompt.

    Always renders the section header so the placeholder is informative even
    when empty (it tells agents the wiki exists and how to write to it).
    ``index`` is the dict loaded from ``wiki_index.json``.
    """
    header = [
        "## Project Wiki",
        "",
        "Durable knowledge across experiments — facts, EDA, methodology, "
        "prior findings. Look here before reasoning from scratch.",
        "",
    ]
    if not index:
        header.append(
            "The project wiki is empty. Add knowledge with "
            "`uv run abreka wiki add --title \"...\" --summary \"...\" --tag <tag> "
            "--content \"...\"`."
        )
        return "\n".join(header)

    entries = sorted(index.values(), key=lambda e: e.get("slug", ""))
    for e in entries:
        slug = e.get("slug", "")
        summary = (e.get("summary") or e.get("title") or "").strip().replace("\n", " ")
        tags = e.get("tags", [])
        line = f"- `{slug}`"
        if summary:
            line += f" — {summary}"
        if tags:
            line += f" ({', '.join(tags)})"
        header.append(line)

    header.extend([
        "",
        "Read a page: `uv run abreka wiki show <slug>`",
        "Search: `uv run abreka wiki search \"<query>\"`",
    ])
    return "\n".join(header)
