"""Deterministic prompt rendering and linting utilities."""

from __future__ import annotations

import re
from typing import Any

from kiessclaw.usecases.registry import get_usecase, validate_usecase

_PLACEHOLDER_RE = re.compile(r"\{\{\s*([a-zA-Z0-9_]+)\s*\}\}")
_VAGUE_PHRASES = (
    "make it better",
    "optimize",
    "improve it",
    "and so on",
    "etc.",
    "etc",
)
_SUCCESS_HINTS = (
    "success criteria",
    "acceptance criteria",
    "done when",
    "output format",
    "must include",
)
_TEMPLATE_ORDER = ("system", "task", "guardrails", "checklist")


def safe_defaults(inputs: dict[str, Any], required_inputs: list[str]) -> dict[str, Any]:
    """Validate required inputs and return normalized payload."""
    normalized = {str(key): value for key, value in (inputs or {}).items()}
    missing = [key for key in required_inputs if key not in normalized or str(normalized[key]).strip() == ""]
    if missing:
        return {
            "ok": False,
            "missing": missing,
            "message": f"Missing required inputs: {', '.join(missing)}",
            "example": {field: f"<{field}>" for field in required_inputs},
        }
    return {"ok": True, "inputs": normalized}


def lint_prompt(text: str) -> dict[str, Any]:
    """Lint rendered prompt quality and return findings."""
    issues: list[str] = []
    missing_placeholders = sorted(set(_PLACEHOLDER_RE.findall(text)))
    if missing_placeholders:
        issues.append("Unresolved placeholders found")

    lowered = text.lower()
    vague = [phrase for phrase in _VAGUE_PHRASES if phrase in lowered]
    if vague:
        issues.append(f"Vague instructions detected: {', '.join(vague)}")

    if not any(hint in lowered for hint in _SUCCESS_HINTS):
        issues.append("No explicit success criteria detected")

    return {
        "valid": len(issues) == 0,
        "issues": issues,
        "missing_placeholders": missing_placeholders,
    }


def render_prompt(
    usecase_id: str,
    template_name: str,
    inputs: dict[str, Any],
    style: str = "strict",
    deterministic: bool = False,
) -> str:
    """Render one template for a given use case using strict placeholder substitution."""
    spec = get_usecase(usecase_id)
    validate_usecase(spec)
    if template_name not in spec.prompt_templates:
        raise KeyError(f"Unknown template '{template_name}' for use case '{usecase_id}'")

    validation = safe_defaults(inputs, spec.required_inputs)
    if not validation["ok"]:
        raise ValueError(validation["message"])

    values = validation["inputs"]
    template = spec.prompt_templates[template_name]
    rendered = _render_placeholders(template, values)

    if style == "strict":
        header = (
            f"[usecase:{spec.id}]\n"
            f"[template:{template_name}]\n"
            f"[mode:{'deterministic' if deterministic else 'standard'}]\n"
        )
        rendered = f"{header}\n{rendered.strip()}"

    return rendered.strip() + "\n"


def render_prompt_pack(
    usecase_id: str,
    inputs: dict[str, Any],
    style: str = "strict",
    deterministic: bool = False,
) -> dict[str, Any]:
    """Render all prompt templates for a use case in stable order."""
    spec = get_usecase(usecase_id)
    validate_usecase(spec)
    validation = safe_defaults(inputs, spec.required_inputs)
    if not validation["ok"]:
        raise ValueError(validation["message"])

    prompts: dict[str, str] = {}
    lint: dict[str, Any] = {}
    for name in _TEMPLATE_ORDER:
        rendered = render_prompt(
            usecase_id=usecase_id,
            template_name=name,
            inputs=validation["inputs"],
            style=style,
            deterministic=deterministic,
        )
        prompts[name] = rendered
        lint[name] = lint_prompt(rendered)

    return {
        "usecase_id": spec.id,
        "style": style,
        "deterministic": deterministic,
        "required_inputs": list(spec.required_inputs),
        "prompts": prompts,
        "lint": lint,
    }


def _render_placeholders(template: str, values: dict[str, Any]) -> str:
    """Replace `{{field}}` placeholders with given values."""

    def _replace(match: re.Match[str]) -> str:
        key = match.group(1)
        if key not in values:
            return match.group(0)
        value = values[key]
        return str(value)

    return _PLACEHOLDER_RE.sub(_replace, template)
