"""Tests for --guidance / --guidance-file CLI feature."""

from __future__ import annotations

from io import StringIO
from pathlib import Path
from unittest.mock import patch

import pytest

from abreka.prompts import format_guidance, get_default_template, render_template


class TestFormatGuidance:
    def test_nonempty_returns_section(self):
        result = format_guidance("Focus on transformers.")
        assert result == "## Researcher Guidance\n\nFocus on transformers."

    def test_empty_returns_empty_string(self):
        assert format_guidance("") == ""

    def test_whitespace_only_returns_empty_string(self):
        assert format_guidance("   \n  ") == ""

    def test_strips_surrounding_whitespace(self):
        result = format_guidance("  some text  \n")
        assert result == "## Researcher Guidance\n\nsome text"

    def test_multiline_preserved(self):
        text = "Line one.\nLine two.\nLine three."
        result = format_guidance(text)
        assert "Line one.\nLine two.\nLine three." in result


class TestGuidanceInDefaultTemplates:
    def test_propose_exploit_has_guidance_placeholder(self):
        template = get_default_template("propose_exploit")
        assert "{{guidance}}" in template

    def test_propose_explore_has_guidance_placeholder(self):
        template = get_default_template("propose_explore")
        assert "{{guidance}}" in template

    def test_guidance_rendered_in_propose_exploit(self):
        template = get_default_template("propose_exploit")
        rendered = render_template(template, {
            "goal": "test goal",
            "primary_metric": "val:accuracy",
            "metric_direction": "maximize",
            "experiment_context": "no experiments",
            "focus_constraint": "",
            "backlog_context": "No backlog ideas.",
            "branch_overview": "",
            "focused_branch_summary": "",
            "guidance": format_guidance("Use attention mechanisms only."),
            "wiki_index": "",
            "reserved_exp_id": "0001",
        })
        assert "## Researcher Guidance" in rendered
        assert "Use attention mechanisms only." in rendered

    def test_guidance_rendered_in_propose_explore(self):
        template = get_default_template("propose_explore")
        rendered = render_template(template, {
            "goal": "test goal",
            "primary_metric": "val:accuracy",
            "metric_direction": "maximize",
            "experiment_context": "no experiments",
            "focus_constraint": "",
            "backlog_context": "No backlog ideas.",
            "branch_overview": "",
            "focused_branch_summary": "",
            "guidance": format_guidance("Try graph neural networks."),
            "wiki_index": "",
            "reserved_exp_id": "0001",
        })
        assert "## Researcher Guidance" in rendered
        assert "Try graph neural networks." in rendered

    def test_empty_guidance_no_section_header(self):
        template = get_default_template("propose_exploit")
        rendered = render_template(template, {
            "goal": "test goal",
            "primary_metric": "val:accuracy",
            "metric_direction": "maximize",
            "experiment_context": "no experiments",
            "focus_constraint": "",
            "backlog_context": "No backlog ideas.",
            "branch_overview": "",
            "focused_branch_summary": "",
            "guidance": format_guidance(""),
            "wiki_index": "",
            "reserved_exp_id": "0001",
        })
        assert "Researcher Guidance" not in rendered


class TestReadGuidanceInteractive:
    def test_reads_until_eof_line(self):
        from abreka.cli.agent.propose import _read_guidance_interactive

        fake_stdin = StringIO("Line one.\nLine two.\nEOF\nThis should not appear.\n")
        with patch("sys.stdin", fake_stdin):
            result = _read_guidance_interactive()
        assert result == "Line one.\nLine two."

    def test_empty_input_before_eof(self):
        from abreka.cli.agent.propose import _read_guidance_interactive

        fake_stdin = StringIO("EOF\n")
        with patch("sys.stdin", fake_stdin):
            result = _read_guidance_interactive()
        assert result == ""


class TestResolveGuidance:
    def test_inline_guidance(self):
        from abreka.cli.agent.propose import _resolve_guidance

        result = _resolve_guidance("Focus on CNNs.", None)
        assert result == "Focus on CNNs."

    def test_guidance_file(self, tmp_path):
        from abreka.cli.agent.propose import _resolve_guidance

        f = tmp_path / "guidance.md"
        f.write_text("Multi-line\nguidance text.")
        result = _resolve_guidance(None, str(f))
        assert result == "Multi-line\nguidance text."

    def test_both_raises(self, tmp_path):
        import click

        from abreka.cli.agent.propose import _resolve_guidance

        f = tmp_path / "guidance.md"
        f.write_text("from file")
        with pytest.raises(click.ClickException, match="mutually exclusive"):
            _resolve_guidance("inline", str(f))

    def test_neither_returns_empty(self):
        from abreka.cli.agent.propose import _resolve_guidance

        result = _resolve_guidance(None, None)
        assert result == ""
