"""Renderer: converts prompt sections into message content strings.

Each section has a render function that produces text. The compiler
calls these after deciding what to include.
"""

from __future__ import annotations

from .types import (
    CoTSpec,
    CoTStrategy,
    ContextBlock,
    Example,
    InputData,
    Instruction,
    OutputSpec,
    Persona,
    Rule,
)


def render_persona(persona: Persona) -> str:
    """Render persona into system message text."""
    parts = [persona.role]

    if persona.tone:
        parts.append(f"Tone: {persona.tone}.")

    if persona.domain:
        parts.append(f"Expertise: {', '.join(persona.domain)}.")

    if persona.anti_patterns:
        parts.append("Avoid: " + "; ".join(persona.anti_patterns) + ".")

    return "\n".join(parts)


def render_rules(rules: list[Rule]) -> str:
    """Render rules into system message text."""
    if not rules:
        return ""

    lines = ["Rules:"]
    for rule in rules:
        lines.append(f"- {rule.constraint}")

    return "\n".join(lines)


def render_output_spec(spec: OutputSpec) -> str:
    """Render output spec into system message text."""
    parts = []

    if spec.format != "plain":
        parts.append(f"Respond in {spec.format} format.")

    if spec.length:
        parts.append(f"Length: {spec.length}.")

    if spec.language:
        parts.append(f"Language: {spec.language}.")

    if spec.constraints:
        for c in spec.constraints:
            parts.append(c)

    return "\n".join(parts) if parts else ""


def render_cot(cot: CoTSpec) -> str:
    """Render chain-of-thought spec into system message text."""
    if cot.strategy == CoTStrategy.NONE:
        return ""

    strategy_text = {
        CoTStrategy.STEP_BY_STEP: "Think step by step before answering.",
        CoTStrategy.STRUCTURED: "Use a structured reasoning framework before answering.",
        CoTStrategy.REACT: "For each step: think about what to do, take an action, observe the result.",
    }

    parts = [strategy_text.get(cot.strategy, "")]

    if cot.format:
        parts.append(cot.format)

    visibility_text = {
        "hidden": "Keep your reasoning internal.",
        "visible": "Show your reasoning in the response.",
        "extracted": "Wrap your reasoning in <reasoning> tags, then give the final answer.",
    }
    parts.append(visibility_text.get(cot.visibility.value, ""))

    return "\n".join(p for p in parts if p)


def render_context_blocks(blocks: list[ContextBlock]) -> str:
    """Render context blocks into user message text."""
    if not blocks:
        return ""

    parts = ["<context>"]
    for block in blocks:
        source_tag = f' source="{block.source}"' if block.source else ""
        parts.append(f"<document{source_tag}>")
        parts.append(block.content)
        parts.append("</document>")
    parts.append("</context>")

    return "\n".join(parts)


def render_examples(examples: list[Example]) -> str:
    """Render few-shot examples into user message text."""
    if not examples:
        return ""

    parts = ["Examples:"]
    for i, ex in enumerate(examples, 1):
        label = "NEGATIVE example (don't do this)" if ex.negative else f"Example {i}"
        parts.append(f"\n{label}:")
        parts.append(f"Input: {ex.input}")
        parts.append(f"Output: {ex.output}")
        if ex.explanation:
            parts.append(f"Why: {ex.explanation}")

    return "\n".join(parts)


def render_instruction(instruction: Instruction) -> str:
    """Render instruction into user message text."""
    parts = [instruction.task]

    if instruction.intent:
        parts.append(f"Purpose: {instruction.intent}")

    if instruction.subtasks:
        parts.append("Steps:")
        for st in instruction.subtasks:
            parts.append(f"  - {st}")

    if instruction.constraints:
        parts.append("Constraints:")
        for c in instruction.constraints:
            parts.append(f"  - {c}")

    return "\n".join(parts)


def render_input_data(data: InputData) -> str:
    """Render input data into user message text."""
    content = data.content if isinstance(data.content, str) else str(data.content)

    delimiter = data.delimiter
    return f"<{data.label}>\n{delimiter}\n{content}\n{delimiter}\n</{data.label}>"
