"""Tests for prompt_builder.renderer"""

from prompt_builder import (
    Persona,
    Rule,
    OutputSpec,
    CoTSpec,
    CoTStrategy,
    Visibility,
    ContextBlock,
    Example,
    Instruction,
    InputData,
    render_persona,
    render_rules,
    render_output_spec,
    render_cot,
    render_context_blocks,
    render_examples,
    render_instruction,
    render_input_data,
)


class TestRenderPersona:
    def test_role_only(self):
        text = render_persona(Persona(role="You are a helpful assistant."))
        assert "You are a helpful assistant." in text

    def test_full_persona(self):
        text = render_persona(Persona(
            role="You are a senior engineer.",
            tone="terse",
            domain=["rust", "systems"],
            anti_patterns=["don't apologize", "no yapping"],
        ))
        assert "senior engineer" in text
        assert "terse" in text.lower()
        assert "rust" in text
        assert "don't apologize" in text


class TestRenderRules:
    def test_empty(self):
        assert render_rules([]) == ""

    def test_single_rule(self):
        text = render_rules([Rule(constraint="Never expose API keys.")])
        assert "Never expose API keys." in text
        assert "Rules:" in text

    def test_multiple_rules(self):
        text = render_rules([
            Rule(constraint="Rule one."),
            Rule(constraint="Rule two."),
        ])
        assert "Rule one." in text
        assert "Rule two." in text


class TestRenderOutputSpec:
    def test_plain_format_empty(self):
        text = render_output_spec(OutputSpec())
        assert text == ""

    def test_json_format(self):
        text = render_output_spec(OutputSpec(format="json"))
        assert "json" in text.lower()

    def test_with_constraints(self):
        text = render_output_spec(OutputSpec(
            format="json",
            length="under 500 tokens",
            constraints=["include confidence score"],
        ))
        assert "json" in text.lower()
        assert "500 tokens" in text
        assert "confidence score" in text


class TestRenderCoT:
    def test_none_strategy(self):
        text = render_cot(CoTSpec(strategy=CoTStrategy.NONE))
        assert text == ""

    def test_step_by_step(self):
        text = render_cot(CoTSpec(
            strategy=CoTStrategy.STEP_BY_STEP,
            visibility=Visibility.VISIBLE,
        ))
        assert "step by step" in text.lower()

    def test_extracted_visibility(self):
        text = render_cot(CoTSpec(
            strategy=CoTStrategy.STEP_BY_STEP,
            visibility=Visibility.EXTRACTED,
        ))
        assert "reasoning" in text.lower()


class TestRenderContextBlocks:
    def test_empty(self):
        assert render_context_blocks([]) == ""

    def test_single_block(self):
        text = render_context_blocks([
            ContextBlock(content="The sky is blue.", source="rag"),
        ])
        assert "<context>" in text
        assert "</context>" in text
        assert "The sky is blue." in text
        assert 'source="rag"' in text

    def test_multiple_blocks(self):
        text = render_context_blocks([
            ContextBlock(content="Fact A.", source="db"),
            ContextBlock(content="Fact B.", source="memory"),
        ])
        assert text.count("<document") == 2
        assert "Fact A." in text
        assert "Fact B." in text


class TestRenderExamples:
    def test_empty(self):
        assert render_examples([]) == ""

    def test_single_example(self):
        text = render_examples([
            Example(input="2+2", output="4"),
        ])
        assert "2+2" in text
        assert "4" in text

    def test_negative_example(self):
        text = render_examples([
            Example(input="bad", output="wrong", negative=True),
        ])
        assert "NEGATIVE" in text or "negative" in text.lower()

    def test_with_explanation(self):
        text = render_examples([
            Example(input="q", output="a", explanation="because reasons"),
        ])
        assert "because reasons" in text


class TestRenderInstruction:
    def test_simple(self):
        text = render_instruction(Instruction(task="Classify this."))
        assert "Classify this." in text

    def test_with_intent(self):
        text = render_instruction(Instruction(
            task="Classify this.",
            intent="Route to correct team.",
        ))
        assert "Route to correct team." in text

    def test_with_subtasks(self):
        text = render_instruction(Instruction(
            task="Review the code.",
            subtasks=["Check types", "Check errors"],
        ))
        assert "Check types" in text
        assert "Check errors" in text

    def test_with_constraints(self):
        text = render_instruction(Instruction(
            task="Summarize.",
            constraints=["Use only provided context"],
        ))
        assert "Use only provided context" in text


class TestRenderInputData:
    def test_simple_string(self):
        text = render_input_data(InputData(content="hello world"))
        assert "hello world" in text
        assert "<input>" in text
        assert "</input>" in text

    def test_custom_label(self):
        text = render_input_data(InputData(
            content="code here",
            label="diff",
            delimiter="```",
        ))
        assert "<diff>" in text
        assert "</diff>" in text
        assert "code here" in text

    def test_dict_content(self):
        text = render_input_data(InputData(content={"key": "value"}))
        assert "key" in text
        assert "value" in text
