"""Integration tests for issue tracker abstraction with worker prompts."""

import pytest

from maniple_mcp.worker_prompt import generate_worker_prompt
from maniple_mcp.issue_tracker import (
    BEADS_BACKEND,
    PEBBLES_BACKEND,
    detect_issue_tracker,
)


class TestTrackerDetectionWithWorkerPrompts:
    """Test that worker prompts use the correct tracker backend."""

    def test_pebbles_project_generates_pb_commands(self, tmp_path):
        """Pebbles project should generate pb commands in worker prompt."""
        # Setup: Create project with .pebbles marker
        project_path = tmp_path / "pebbles-repo"
        project_path.mkdir()
        (project_path / ".pebbles").mkdir()

        # Verify detection
        backend = detect_issue_tracker(str(project_path))
        assert backend == PEBBLES_BACKEND

        # Generate worker prompt with issue ID
        issue_id = "cic-123"
        prompt = generate_worker_prompt(
            "test-session",
            "TestWorker",
            issue_id=issue_id,
            project_path=str(project_path),
        )

        # Assert: Prompt should contain Pebbles commands
        assert "pb update cic-123 -status in_progress" in prompt
        assert "pb close cic-123" in prompt
        assert "pb show cic-123" in prompt
        assert "Use the pebbles CLI (`pb`)" in prompt

        # Assert: Should NOT contain Beads commands
        assert "bd --no-db" not in prompt
        assert "beads CLI" not in prompt.lower()

    def test_beads_project_generates_bd_commands(self, tmp_path):
        """Beads project should generate bd --no-db commands in worker prompt."""
        # Setup: Create project with .beads marker
        project_path = tmp_path / "beads-repo"
        project_path.mkdir()
        (project_path / ".beads").mkdir()

        # Verify detection
        backend = detect_issue_tracker(str(project_path))
        assert backend == BEADS_BACKEND

        # Generate worker prompt with issue ID
        issue_id = "cic-456"
        prompt = generate_worker_prompt(
            "test-session",
            "TestWorker",
            issue_id=issue_id,
            project_path=str(project_path),
        )

        # Assert: Prompt should contain Beads commands
        assert "bd --no-db update cic-456 --status in_progress" in prompt
        assert "bd --no-db close cic-456" in prompt
        assert "bd --no-db show cic-456" in prompt
        assert "Use the beads CLI (`bd`)" in prompt

        # Assert: Should NOT contain Pebbles commands
        assert "pb update" not in prompt
        assert "pb close" not in prompt
        assert "pebbles CLI" not in prompt.lower()

    def test_both_markers_defaults_to_pebbles(self, tmp_path, caplog):
        """Project with both markers should default to Pebbles with warning."""
        # Setup: Create project with both markers
        project_path = tmp_path / "both-markers-repo"
        project_path.mkdir()
        (project_path / ".beads").mkdir()
        (project_path / ".pebbles").mkdir()

        # Verify detection
        backend = detect_issue_tracker(str(project_path))
        assert backend == PEBBLES_BACKEND
        assert "defaulting to pebbles" in caplog.text

        # Generate worker prompt
        issue_id = "cic-789"
        prompt = generate_worker_prompt(
            "test-session",
            "TestWorker",
            issue_id=issue_id,
            project_path=str(project_path),
        )

        # Assert: Should use Pebbles commands
        assert "pb update cic-789" in prompt
        assert "pb close cic-789" in prompt
        assert "Use the pebbles CLI (`pb`)" in prompt

        # Assert: Should NOT use Beads commands
        assert "bd --no-db" not in prompt

    def test_no_tracker_shows_generic_instructions(self, tmp_path):
        """Project with no tracker should show generic instructions."""
        # Setup: Create project with no tracker markers
        project_path = tmp_path / "no-tracker-repo"
        project_path.mkdir()

        # Verify detection
        backend = detect_issue_tracker(str(project_path))
        assert backend is None

        # Generate worker prompt with issue ID
        issue_id = "cic-abc"
        prompt = generate_worker_prompt(
            "test-session",
            "TestWorker",
            issue_id=issue_id,
            project_path=str(project_path),
        )

        # Assert: Should have generic instructions
        assert "Mark in progress in the issue tracker" in prompt
        assert "Close the issue when done" in prompt
        assert "No issue tracker detected" in prompt
        assert "Supported trackers:" in prompt

        # Assert: Should NOT contain specific tracker commands
        assert "pb update" not in prompt
        assert "bd --no-db update" not in prompt
        assert "Use the pebbles CLI" not in prompt
        assert "Use the beads CLI" not in prompt

    def test_no_project_path_shows_generic_instructions(self):
        """Worker without project_path should show generic instructions."""
        # Generate worker prompt without project_path
        issue_id = "cic-xyz"
        prompt = generate_worker_prompt(
            "test-session",
            "TestWorker",
            issue_id=issue_id,
            project_path=None,
        )

        # Assert: Should have generic instructions
        assert "Mark in progress in the issue tracker" in prompt
        assert "Close the issue when done" in prompt
        assert "No issue tracker detected" in prompt

        # Assert: Should NOT contain specific tracker commands
        assert "pb update" not in prompt
        assert "bd --no-db update" not in prompt


class TestCommandTemplateFormatting:
    """Test that command templates are correctly formatted with parameters."""

    def test_pebbles_update_command_formatting(self, tmp_path):
        """Pebbles update command should use -status flag."""
        project_path = tmp_path / "pebbles-repo"
        project_path.mkdir()
        (project_path / ".pebbles").mkdir()

        prompt = generate_worker_prompt(
            "test",
            "Worker",
            issue_id="cic-test",
            project_path=str(project_path),
        )

        # Pebbles uses -status, not --status
        assert "pb update cic-test -status in_progress" in prompt
        assert "pb update cic-test --status" not in prompt

    def test_beads_update_command_formatting(self, tmp_path):
        """Beads update command should use --status flag."""
        project_path = tmp_path / "beads-repo"
        project_path.mkdir()
        (project_path / ".beads").mkdir()

        prompt = generate_worker_prompt(
            "test",
            "Worker",
            issue_id="cic-test",
            project_path=str(project_path),
        )

        # Beads uses --status
        assert "bd --no-db update cic-test --status in_progress" in prompt
        assert "bd --no-db update cic-test -status" not in prompt

    def test_pebbles_show_command_in_assignment(self, tmp_path):
        """Pebbles show command should appear in assignment section."""
        project_path = tmp_path / "pebbles-repo"
        project_path.mkdir()
        (project_path / ".pebbles").mkdir()

        prompt = generate_worker_prompt(
            "test",
            "Worker",
            issue_id="cic-show-test",
            project_path=str(project_path),
        )

        # Should mention pb show in assignment
        assert "pb show cic-show-test" in prompt
        assert "for details" in prompt

    def test_beads_show_command_in_assignment(self, tmp_path):
        """Beads show command should appear in assignment section."""
        project_path = tmp_path / "beads-repo"
        project_path.mkdir()
        (project_path / ".beads").mkdir()

        prompt = generate_worker_prompt(
            "test",
            "Worker",
            issue_id="cic-show-test",
            project_path=str(project_path),
        )

        # Should mention bd show in assignment
        assert "bd --no-db show cic-show-test" in prompt
        assert "for details" in prompt


class TestCodexAgentTrackerIntegration:
    """Test tracker abstraction works for Codex agents."""

    def test_codex_pebbles_project_uses_pb_commands(self, tmp_path):
        """Codex worker in Pebbles project should use pb commands."""
        project_path = tmp_path / "pebbles-repo"
        project_path.mkdir()
        (project_path / ".pebbles").mkdir()

        prompt = generate_worker_prompt(
            "test",
            "CodexWorker",
            agent_type="codex",
            issue_id="cic-123",
            project_path=str(project_path),
        )

        # Should use Pebbles commands
        assert "pb update cic-123 -status in_progress" in prompt
        assert "pb close cic-123" in prompt
        assert "Use the pebbles CLI (`pb`)" in prompt

        # Should NOT use Beads commands
        assert "bd --no-db" not in prompt

    def test_codex_beads_project_uses_bd_commands(self, tmp_path):
        """Codex worker in Beads project should use bd commands."""
        project_path = tmp_path / "beads-repo"
        project_path.mkdir()
        (project_path / ".beads").mkdir()

        prompt = generate_worker_prompt(
            "test",
            "CodexWorker",
            agent_type="codex",
            issue_id="cic-456",
            project_path=str(project_path),
        )

        # Should use Beads commands
        assert "bd --no-db update cic-456 --status in_progress" in prompt
        assert "bd --no-db close cic-456" in prompt
        assert "Use the beads CLI (`bd`)" in prompt

        # Should NOT use Pebbles commands
        assert "pb update" not in prompt


class TestTrackerWorkflowSteps:
    """Test that tracker workflow steps are correctly numbered and ordered."""

    def test_workflow_numbered_as_step_4(self, tmp_path):
        """Tracker workflow should be step 4 in the prompt."""
        project_path = tmp_path / "pebbles-repo"
        project_path.mkdir()
        (project_path / ".pebbles").mkdir()

        prompt = generate_worker_prompt(
            "test",
            "Worker",
            issue_id="cic-123",
            project_path=str(project_path),
        )

        # Should be numbered as step 4
        assert "4. **Issue tracker workflow.**" in prompt

    def test_commit_step_appears_with_worktree_no_issue(self, tmp_path):
        """Commit step should appear as step 4 when worktree but no issue."""
        project_path = tmp_path / "pebbles-repo"
        project_path.mkdir()
        (project_path / ".pebbles").mkdir()

        prompt = generate_worker_prompt(
            "test",
            "Worker",
            use_worktree=True,
            project_path=str(project_path),
        )

        # Should have commit step
        assert "4. **Commit when done.**" in prompt
        assert "cherry-pick" in prompt

    def test_no_extra_steps_without_issue_or_worktree(self, tmp_path):
        """No extra numbered steps when no issue or worktree."""
        project_path = tmp_path / "pebbles-repo"
        project_path.mkdir()
        (project_path / ".pebbles").mkdir()

        prompt = generate_worker_prompt(
            "test",
            "Worker",
            project_path=str(project_path),
        )

        # Should not have step 4
        assert "4." not in prompt

    def test_workflow_includes_all_steps_in_order(self, tmp_path):
        """Tracker workflow should include all steps in correct order."""
        project_path = tmp_path / "pebbles-repo"
        project_path.mkdir()
        (project_path / ".pebbles").mkdir()

        prompt = generate_worker_prompt(
            "test",
            "Worker",
            issue_id="cic-123",
            project_path=str(project_path),
        )

        # Find the workflow section
        workflow_start = prompt.index("4. **Issue tracker workflow.**")
        workflow_section = prompt[workflow_start:workflow_start + 500]

        # Check order of steps
        mark_in_progress_pos = workflow_section.index("Mark in progress:")
        implement_pos = workflow_section.index("Implement the changes")
        close_pos = workflow_section.index("Close issue:")
        commit_pos = workflow_section.index("Commit with issue reference:")

        # Verify order
        assert mark_in_progress_pos < implement_pos < close_pos < commit_pos


class TestTrackerCommitInstructions:
    """Test tracker-specific commit message formatting."""

    def test_pebbles_commit_includes_issue_id(self, tmp_path):
        """Pebbles workflow should include issue ID in commit message."""
        project_path = tmp_path / "pebbles-repo"
        project_path.mkdir()
        (project_path / ".pebbles").mkdir()

        prompt = generate_worker_prompt(
            "test",
            "Worker",
            issue_id="cic-commit",
            project_path=str(project_path),
        )

        # Should instruct to include issue ID
        assert 'git commit -m "cic-commit:' in prompt

    def test_beads_commit_includes_issue_id(self, tmp_path):
        """Beads workflow should include issue ID in commit message."""
        project_path = tmp_path / "beads-repo"
        project_path.mkdir()
        (project_path / ".beads").mkdir()

        prompt = generate_worker_prompt(
            "test",
            "Worker",
            issue_id="cic-commit",
            project_path=str(project_path),
        )

        # Should instruct to include issue ID
        assert 'git commit -m "cic-commit:' in prompt
