"""Tests for checklist generator."""

import pytest
from pathlib import Path
from cafe.utils.checklist_generator import (
    generate_spec_checklist,
    generate_plan_checklist,
    generate_develop_checklist,
    generate_review_checklist,
    generate_pr_checklist,
)


class TestGenerateSpecChecklist:
    """Tests for generate_spec_checklist function."""

    def test_generates_spec_checklist_iteration_1(self, tmp_path):
        """Test generates spec checklist for iteration 1."""
        checklist_path = tmp_path / "checklist.md"

        generate_spec_checklist(
            iteration=1,
            agent_name="Roger",
            current_spec_file=".cafe/issues/test/spec/iteration_001/output.md",
            prev_spec_file=None,
            checklist_file_path=checklist_path,
        )

        assert checklist_path.exists()
        content = checklist_path.read_text()
        assert "## Checklist" in content
        assert ".cafe/issues/test/spec/iteration_001/output.md" in content
        assert "Read README.md" in content  # Iteration 1 specific

    def test_generates_spec_checklist_iteration_n(self, tmp_path):
        """Test generates spec checklist for iteration N."""
        checklist_path = tmp_path / "checklist.md"

        generate_spec_checklist(
            iteration=2,
            agent_name="Roger",
            current_spec_file=".cafe/issues/test/spec/iteration_002/output.md",
            prev_spec_file=".cafe/issues/test/spec/iteration_001/output.md",
            checklist_file_path=checklist_path,
        )

        assert checklist_path.exists()
        content = checklist_path.read_text()
        assert ".cafe/issues/test/spec/iteration_001/output.md" in content
        assert ".cafe/issues/test/spec/iteration_002/output.md" in content
        assert "Review user's answer" in content  # Iteration N specific

    def test_adds_iteration_4_plus_constraint(self, tmp_path):
        """Test adds constraint for iteration 4+."""
        checklist_path = tmp_path / "checklist.md"

        generate_spec_checklist(
            iteration=4,
            agent_name="Roger",
            current_spec_file=".cafe/issues/test/spec/iteration_004/output.md",
            prev_spec_file=".cafe/issues/test/spec/iteration_003/output.md",
            checklist_file_path=checklist_path,
        )

        content = checklist_path.read_text()
        assert "Round 4" in content
        assert "Only clarify existing questions" in content


class TestGeneratePlanChecklist:
    """Tests for generate_plan_checklist function."""

    def test_generates_plan_checklist(self, tmp_path):
        """Test generates plan checklist."""
        checklist_path = tmp_path / "checklist.md"

        generate_plan_checklist(
            agent_name="Nick",
            plan_file_path=".cafe/issues/test/plan/iteration_001/output.md",
            spec_file_path=".cafe/issues/test/spec/iteration_001/output.md",
            checklist_file_path=checklist_path,
        )

        assert checklist_path.exists()
        content = checklist_path.read_text()
        assert "## Checklist" in content
        assert ".cafe/issues/test/plan/iteration_001/output.md" in content
        assert ".cafe/issues/test/spec/iteration_001/output.md" in content
        assert "planning, not implementation" in content


class TestGenerateDevelopChecklist:
    """Tests for generate_develop_checklist function."""

    def test_generates_develop_checklist_normal_mode(self, tmp_path):
        """Test generates develop checklist in normal mode."""
        checklist_path = tmp_path / "checklist.md"

        generate_develop_checklist(
            agent_name="David",
            spec_file_path=".cafe/issues/test/spec/iteration_001/output.md",
            plan_file_path=".cafe/issues/test/plan/iteration_001/output.md",
            develop_file=None,
            checklist_file_path=checklist_path,
            correction_mode=False,
        )

        assert checklist_path.exists()
        content = checklist_path.read_text()
        assert "## Checklist" in content
        assert "Execute development tasks in strict order" in content

    def test_generates_develop_checklist_correction_mode(self, tmp_path):
        """Test generates develop checklist in correction mode."""
        checklist_path = tmp_path / "checklist.md"

        generate_develop_checklist(
            agent_name="David",
            spec_file_path=".cafe/issues/test/spec/iteration_001/output.md",
            plan_file_path=".cafe/issues/test/plan/iteration_001/output.md",
            develop_file=".cafe/issues/test/develop/iteration_001/output.md",
            checklist_file_path=checklist_path,
            correction_mode=True,
        )

        assert checklist_path.exists()
        content = checklist_path.read_text()
        assert ".cafe/issues/test/develop/iteration_001/output.md" in content
        assert "Address each issue raised in the feedback" in content

    def test_develop_checklist_correction_mode_uses_unified_feedback_file_path(self, tmp_path):
        """Test that correction mode uses {feedback_file_path} instead of separate review/PR paths."""
        checklist_path = tmp_path / "checklist.md"

        generate_develop_checklist(
            agent_name="David",
            spec_file_path=".cafe/issues/test/spec/iteration_001/output.md",
            plan_file_path=".cafe/issues/test/plan/iteration_001/output.md",
            develop_file=None,
            checklist_file_path=checklist_path,
            correction_mode=True,
            feedback_file_path=".cafe/issues/test/review/iteration_001/output.md",
        )

        assert checklist_path.exists()
        content = checklist_path.read_text()
        # Should have unified feedback_file_path
        assert ".cafe/issues/test/review/iteration_001/output.md" in content
        assert "Read feedback todo list" in content
        assert "Mark completed items" in content
        # Should NOT have separate review_file_path or pr_feedback_file_path placeholders
        assert "{review_file_path}" not in content
        assert "{pr_feedback_file_path}" not in content


class TestGenerateReviewChecklist:
    """Tests for generate_review_checklist function."""

    def test_generates_review_checklist(self, tmp_path):
        """Test generates review checklist."""
        checklist_path = tmp_path / "checklist.md"

        generate_review_checklist(
            agent_name="Richard",
            spec_file_path=".cafe/issues/test/spec/iteration_001/output.md",
            review_file_path=".cafe/issues/test/review/iteration_001/output.md",
            base_branch="main",
            checklist_file_path=checklist_path,
        )

        assert checklist_path.exists()
        content = checklist_path.read_text()
        assert "## Checklist" in content
        assert ".cafe/issues/test/review/iteration_001/output.md" in content
        assert "git log main..HEAD" in content


    def test_review_checklist_includes_commit_message_checking(self, tmp_path):
        """Test that review checklist always includes commit message checking steps."""
        checklist_path = tmp_path / "checklist.md"

        generate_review_checklist(
            agent_name="Richard",
            spec_file_path=".cafe/issues/test/spec/iteration_001/output.md",
            review_file_path=".cafe/issues/test/review/iteration_001/output.md",
            base_branch="main",
            checklist_file_path=checklist_path,
        )

        content = checklist_path.read_text()
        # Verify commit message checking steps are present
        assert "git log main..HEAD" in content

    def test_review_checklist_includes_todo_list_format_instructions(self, tmp_path):
        """Test that review checklist includes instructions to output in todo list format."""
        checklist_path = tmp_path / "checklist.md"

        generate_review_checklist(
            agent_name="Richard",
            spec_file_path=".cafe/issues/test/spec/iteration_001/output.md",
            review_file_path=".cafe/issues/test/review/iteration_001/output.md",
            base_branch="main",
            checklist_file_path=checklist_path,
        )

        content = checklist_path.read_text()
        # Verify todo list format instructions are present
        assert "## Todo List" in content
        assert "- [ ]" in content
        assert "- [x]" in content


class TestGeneratePRChecklist:
    """Tests for generate_pr_checklist function."""

    def test_generates_pr_checklist(self, tmp_path):
        """Test generates PR checklist."""
        checklist_path = tmp_path / "checklist.md"

        generate_pr_checklist(
            agent_name="David",
            spec_file_path=".cafe/issues/test/spec/iteration_001/output.md",
            plan_file_path=".cafe/issues/test/plan/iteration_001/output.md",
            pr_file=".cafe/issues/test/pr/iteration_001/output.md",
            checklist_file_path=checklist_path,
        )

        assert checklist_path.exists()
        content = checklist_path.read_text()
        assert "## Checklist" in content
        assert ".cafe/issues/test/pr/iteration_001/output.md" in content


class TestChecklistFileCreation:
    """Tests for checklist file creation behavior."""

    def test_creates_parent_directories_automatically(self, tmp_path):
        """Test creates parent directories if they don't exist."""
        checklist_path = tmp_path / "nested" / "dir" / "checklist.md"

        generate_spec_checklist(
            iteration=1,
            agent_name="Roger",
            current_spec_file=".cafe/issues/test/spec/iteration_001/output.md",
            prev_spec_file=None,
            checklist_file_path=checklist_path,
        )

        assert checklist_path.exists()
        assert checklist_path.parent.exists()

    def test_resolves_agent_guidelines_from_real_agent_file(self, tmp_path):
        """Test resolves agent guidelines from actual agent file."""
        checklist_path = tmp_path / "checklist.md"

        # Use a real agent name that exists in the system
        generate_spec_checklist(
            iteration=1,
            agent_name="Roger",
            current_spec_file=".cafe/issues/test/spec/iteration_001/output.md",
            prev_spec_file=None,
            checklist_file_path=checklist_path,
        )

        content = checklist_path.read_text()
        # Should have agent guidelines checklist section
        assert "## Agent Guidelines Checklist" in content


class TestBasicPrinciples:
    """Tests for basic principles in checklists."""

    def test_spec_checklist_with_basic_principles(self, tmp_path):
        """Test spec checklist includes basic principles when provided."""
        checklist_path = tmp_path / "checklist.md"

        basic_principles = """- Write in native language
- No technical details"""

        generate_spec_checklist(
            iteration=1,
            agent_name="Roger",
            current_spec_file=".cafe/issues/test/spec/iteration_001/output.md",
            prev_spec_file=None,
            checklist_file_path=checklist_path,
            basic_principles=basic_principles,
        )

        content = checklist_path.read_text()
        assert "## Basic Principles" in content
        assert "[ ] Write in native language" in content
        assert "[ ] No technical details" in content

    def test_spec_checklist_with_template_file(self, tmp_path):
        """Test spec checklist includes template instruction when provided in manual mode."""
        checklist_path = tmp_path / "checklist.md"

        generate_spec_checklist(
            iteration=1,
            agent_name="Roger",
            current_spec_file=".cafe/issues/test/spec/iteration_001/output.md",
            prev_spec_file=None,
            checklist_file_path=checklist_path,
            template_file=".cafe/templates/spec.md",
            template_mode="manual",
        )

        content = checklist_path.read_text()
        assert ".cafe/templates/spec.md" in content

    def test_spec_checklist_auto_template_mode(self, tmp_path):
        """Test spec checklist lists available templates in auto mode."""
        checklist_path = tmp_path / "checklist.md"

        generate_spec_checklist(
            iteration=1,
            agent_name="Roger",
            current_spec_file=".cafe/issues/test/spec/iteration_001/output.md",
            prev_spec_file=None,
            checklist_file_path=checklist_path,
            template_mode="auto",
        )

        content = checklist_path.read_text()
        assert "Pick a most suitable spec template" in content

    def test_plan_checklist_with_basic_principles(self, tmp_path):
        """Test plan checklist includes basic principles when provided."""
        checklist_path = tmp_path / "checklist.md"

        basic_principles = """- Write plan content in your native language"""

        generate_plan_checklist(
            agent_name="Nick",
            plan_file_path=".cafe/issues/test/plan/iteration_001/output.md",
            spec_file_path=".cafe/issues/test/spec/iteration_001/output.md",
            checklist_file_path=checklist_path,
            basic_principles=basic_principles,
        )

        content = checklist_path.read_text()
        assert "## Basic Principles" in content
        assert "[ ] Write plan content in your native language" in content

    def test_plan_checklist_auto_template_mode(self, tmp_path):
        """Test plan checklist lists available templates in auto mode."""
        checklist_path = tmp_path / "checklist.md"

        generate_plan_checklist(
            agent_name="Nick",
            plan_file_path=".cafe/issues/test/plan/iteration_001/output.md",
            spec_file_path=".cafe/issues/test/spec/iteration_001/output.md",
            checklist_file_path=checklist_path,
            template_mode="auto",
        )

        content = checklist_path.read_text()
        assert "Pick a most suitable plan template" in content

    def test_develop_checklist_with_basic_principles(self, tmp_path):
        """Test develop checklist includes basic principles when provided."""
        checklist_path = tmp_path / "checklist.md"

        basic_principles = """- Follow existing commit message style
- Use same language as existing code comments
- Maximize code reuse"""

        generate_develop_checklist(
            agent_name="David",
            spec_file_path=".cafe/issues/test/spec/iteration_001/output.md",
            plan_file_path=".cafe/issues/test/plan/iteration_001/output.md",
            develop_file=None,
            checklist_file_path=checklist_path,
            correction_mode=False,
            basic_principles=basic_principles,
        )

        content = checklist_path.read_text()
        assert "## Basic Principles" in content
        assert "[ ] Follow existing commit message style" in content
        assert "[ ] Use same language as existing code comments" in content
        assert "[ ] Maximize code reuse" in content

    def test_pr_checklist_with_basic_principles(self, tmp_path):
        """Test PR checklist includes basic principles when provided."""
        checklist_path = tmp_path / "checklist.md"

        basic_principles = """- Use same language as commit messages"""

        generate_pr_checklist(
            agent_name="David",
            spec_file_path=".cafe/issues/test/spec/iteration_001/output.md",
            plan_file_path=".cafe/issues/test/plan/iteration_001/output.md",
            pr_file=".cafe/issues/test/pr/iteration_001/output.md",
            checklist_file_path=checklist_path,
            basic_principles=basic_principles,
        )

        content = checklist_path.read_text()
        assert "## Basic Principles" in content
        assert "[ ] Use same language as commit messages" in content

    def test_checklist_without_basic_principles(self, tmp_path):
        """Test checklist works without basic principles (backward compatibility)."""
        checklist_path = tmp_path / "checklist.md"

        generate_spec_checklist(
            iteration=1,
            agent_name="Roger",
            current_spec_file=".cafe/issues/test/spec/iteration_001/output.md",
            prev_spec_file=None,
            checklist_file_path=checklist_path,
            basic_principles=None,
        )

        content = checklist_path.read_text()
        # Should not have basic principles section
        assert "## Basic Principles" not in content
        # But should still have the main checklist
        assert "## Checklist" in content


class TestSpecChecklistXmlInstructions:
    """測試 spec checklist 包含 XML 問題檔產出指示"""

    def test_iteration_1_contains_xml_instructions(self, tmp_path):
        """測試 iteration 1 checklist 包含 XML 問題檔指示"""
        checklist_path = tmp_path / "checklist.md"

        generate_spec_checklist(
            iteration=1,
            agent_name="Roger",
            current_spec_file=".cafe/issues/test/spec/iteration_001/output.md",
            prev_spec_file=None,
            checklist_file_path=checklist_path,
            questions_xml_file=".cafe/issues/test/spec/iteration_001/questions.xml",
        )

        content = checklist_path.read_text()
        assert "questions.xml" in content
        assert "<questions>" in content
        assert "<question" in content
        assert "CAFE_NEED_CLARIFICATION" in content

    def test_iteration_n_contains_xml_instructions(self, tmp_path):
        """測試 iteration N checklist 包含 XML 問題檔指示"""
        checklist_path = tmp_path / "checklist.md"

        generate_spec_checklist(
            iteration=2,
            agent_name="Roger",
            current_spec_file=".cafe/issues/test/spec/iteration_002/output.md",
            prev_spec_file=".cafe/issues/test/spec/iteration_001/output.md",
            checklist_file_path=checklist_path,
            questions_xml_file=".cafe/issues/test/spec/iteration_002/questions.xml",
        )

        content = checklist_path.read_text()
        assert "questions.xml" in content
        assert "<questions>" in content

    def test_no_xml_instructions_without_questions_xml_file(self, tmp_path):
        """測試不提供 questions_xml_file 時不包含 XML 指示（向後相容）"""
        checklist_path = tmp_path / "checklist.md"

        generate_spec_checklist(
            iteration=1,
            agent_name="Roger",
            current_spec_file=".cafe/issues/test/spec/iteration_001/output.md",
            prev_spec_file=None,
            checklist_file_path=checklist_path,
        )

        content = checklist_path.read_text()
        assert "questions.xml" not in content

    def test_xml_instructions_require_native_language(self, tmp_path):
        """測試 XML 指示要求用 agent 母語撰寫問題"""
        checklist_path = tmp_path / "checklist.md"

        generate_spec_checklist(
            iteration=1,
            agent_name="Roger",
            current_spec_file=".cafe/issues/test/spec/iteration_001/output.md",
            prev_spec_file=None,
            checklist_file_path=checklist_path,
            questions_xml_file=".cafe/issues/test/spec/iteration_001/questions.xml",
        )

        content = checklist_path.read_text()
        assert "questions.xml" in content
        # 驗證 Rules 部分要求用母語撰寫問題
        assert "Rules:" in content
        # 檢查 Rules 後面有提到母語要求
        rules_section = content.split("Rules:")[1].split("```")[0]
        assert "native language" in rules_section.lower()
