"""Tests for PlanDetailScreen.execute_command."""

from pathlib import Path

from erk.tui.app import PlanDetailScreen
from erk.tui.data.types import PlanRowData
from erk_shared.gateway.command_executor.fake import FakeCommandExecutor
from erk_shared.gateway.plan_data_provider.fake import make_plan_row


class TestExecuteCommandBrowserCommands:
    """Tests for browser-related commands."""

    def test_open_browser_opens_pr_url_when_available(self) -> None:
        """open_browser opens PR URL when PR is available."""
        row = make_plan_row(
            123,
            "Test",
            pr_url="https://github.com/test/repo/pull/456",
            issue_url="https://github.com/test/repo/issues/123",
        )
        executor = FakeCommandExecutor()
        screen = PlanDetailScreen(row=row, executor=executor)
        screen.execute_command("open_browser")
        assert executor.opened_urls == ["https://github.com/test/repo/pull/456"]

    def test_open_browser_opens_issue_url_when_no_pr(self) -> None:
        """open_browser opens issue URL when no PR is available."""
        row = make_plan_row(123, "Test", issue_url="https://github.com/test/repo/issues/123")
        executor = FakeCommandExecutor()
        screen = PlanDetailScreen(row=row, executor=executor)
        screen.execute_command("open_browser")
        assert executor.opened_urls == ["https://github.com/test/repo/issues/123"]

    def test_open_issue_opens_issue_url(self) -> None:
        """open_issue opens the issue URL."""
        row = make_plan_row(123, "Test", issue_url="https://github.com/test/repo/issues/123")
        executor = FakeCommandExecutor()
        screen = PlanDetailScreen(row=row, executor=executor)
        screen.execute_command("open_issue")
        assert executor.opened_urls == ["https://github.com/test/repo/issues/123"]
        assert "Opened issue #123" in executor.notifications

    def test_open_pr_opens_pr_url(self) -> None:
        """open_pr opens the PR URL."""
        row = make_plan_row(
            123,
            "Test",
            pr_number=456,
            pr_url="https://github.com/test/repo/pull/456",
        )
        executor = FakeCommandExecutor()
        screen = PlanDetailScreen(row=row, executor=executor)
        screen.execute_command("open_pr")
        assert executor.opened_urls == ["https://github.com/test/repo/pull/456"]
        assert "Opened PR #456" in executor.notifications

    def test_open_run_opens_run_url(self) -> None:
        """open_run opens the workflow run URL."""
        row = make_plan_row(
            123,
            "Test",
            run_url="https://github.com/test/repo/actions/runs/789",
        )
        executor = FakeCommandExecutor()
        screen = PlanDetailScreen(row=row, executor=executor)
        screen.execute_command("open_run")
        assert executor.opened_urls == ["https://github.com/test/repo/actions/runs/789"]


class TestExecuteCommandCopyCommands:
    """Tests for copy-related commands."""

    def test_copy_checkout_copies_command(self) -> None:
        """copy_checkout copies branch checkout command."""
        row = make_plan_row(
            123,
            "Test",
            worktree_name="feature-123",
            worktree_branch="feature-123",
            exists_locally=True,
        )
        executor = FakeCommandExecutor()
        screen = PlanDetailScreen(row=row, executor=executor)
        screen.execute_command("copy_checkout")
        assert executor.copied_texts == ["erk br co feature-123"]
        assert "Copied: erk br co feature-123" in executor.notifications

    def test_copy_checkout_notifies_when_worktree_branch_none(self) -> None:
        """copy_checkout shows notification when worktree_branch is None."""
        row = make_plan_row(123, "Test")  # worktree_branch defaults to None
        executor = FakeCommandExecutor()
        screen = PlanDetailScreen(row=row, executor=executor)
        screen.execute_command("copy_checkout")
        # Should not copy anything
        assert executor.copied_texts == []
        # Should show notification
        expected_msg = "No branch associated with this plan is checked out in a local worktree"
        assert expected_msg in executor.notifications

    def test_copy_pr_checkout_copies_command(self) -> None:
        """copy_pr_checkout copies the PR checkout command."""
        row = make_plan_row(123, "Test", pr_number=456)
        executor = FakeCommandExecutor()
        screen = PlanDetailScreen(row=row, executor=executor)
        screen.execute_command("copy_pr_checkout")
        assert executor.copied_texts == ["erk pr co 456"]
        assert "Copied: erk pr co 456" in executor.notifications

    def test_copy_prepare_copies_command(self) -> None:
        """copy_prepare copies the prepare command."""
        row = make_plan_row(123, "Test")
        executor = FakeCommandExecutor()
        screen = PlanDetailScreen(row=row, executor=executor)
        screen.execute_command("copy_prepare")
        assert executor.copied_texts == ["erk prepare 123"]
        assert "Copied: erk prepare 123" in executor.notifications

    def test_copy_submit_copies_command(self) -> None:
        """copy_submit copies the submit command."""
        row = make_plan_row(123, "Test")
        executor = FakeCommandExecutor()
        screen = PlanDetailScreen(row=row, executor=executor)
        screen.execute_command("copy_submit")
        assert executor.copied_texts == ["erk plan submit 123"]
        assert "Copied: erk plan submit 123" in executor.notifications


class TestExecuteCommandClosePlan:
    """Tests for close_plan command.

    Note: close_plan now uses in-process HTTP client (no subprocess).
    These tests verify the guard conditions. The HTTP client behavior
    is tested in tests/tui/data/test_provider.py.
    """

    def test_close_plan_does_nothing_without_issue_url(self) -> None:
        """close_plan does nothing if no issue URL."""
        # Create row directly to set issue_url=None (make_plan_row defaults it)
        row = PlanRowData(
            issue_number=123,
            issue_url=None,  # Explicitly None
            title="Test",
            pr_number=None,
            pr_url=None,
            pr_display="-",
            checks_display="-",
            worktree_name="",
            exists_locally=False,
            local_impl_display="-",
            remote_impl_display="-",
            run_id_display="-",
            run_state_display="-",
            run_url=None,
            full_title="Test",
            issue_body="",
            pr_title=None,
            pr_state=None,
            pr_head_branch=None,
            worktree_branch=None,
            last_local_impl_at=None,
            last_remote_impl_at=None,
            run_id=None,
            run_status=None,
            run_conclusion=None,
            log_entries=(),
            resolved_comment_count=0,
            total_comment_count=0,
            comments_display="-",
            learn_status=None,
            learn_plan_issue=None,
            learn_plan_issue_closed=None,
            learn_plan_pr=None,
            learn_run_url=None,
            learn_display="- not started",
            learn_display_icon="-",
            objective_issue=None,
            objective_display="-",
        )
        executor = FakeCommandExecutor()
        screen = PlanDetailScreen(row=row, executor=executor)
        screen.execute_command("close_plan")
        assert executor.refresh_count == 0


class TestExecuteCommandSubmitToQueue:
    """Tests for submit_to_queue command.

    Note: submit_to_queue now uses streaming output via subprocess when repo_root
    is provided. These tests verify the guard conditions but actual streaming
    behavior is tested via integration tests.
    """

    def test_submit_to_queue_does_nothing_without_repo_root(self) -> None:
        """submit_to_queue does nothing if repo_root is not provided."""
        row = make_plan_row(123, "Test", issue_url="https://github.com/test/repo/issues/123")
        executor = FakeCommandExecutor()
        # repo_root not provided - streaming command should not execute
        screen = PlanDetailScreen(row=row, executor=executor)
        screen.execute_command("submit_to_queue")
        # No executor methods should be called (streaming is independent)
        assert executor.refresh_count == 0

    def test_submit_to_queue_does_nothing_without_issue_url(self) -> None:
        """submit_to_queue does nothing if no issue URL."""
        row = PlanRowData(
            issue_number=123,
            issue_url=None,  # Explicitly None
            title="Test",
            pr_number=None,
            pr_url=None,
            pr_display="-",
            checks_display="-",
            worktree_name="",
            exists_locally=False,
            local_impl_display="-",
            remote_impl_display="-",
            run_id_display="-",
            run_state_display="-",
            run_url=None,
            full_title="Test",
            issue_body="",
            pr_title=None,
            pr_state=None,
            pr_head_branch=None,
            worktree_branch=None,
            last_local_impl_at=None,
            last_remote_impl_at=None,
            run_id=None,
            run_status=None,
            run_conclusion=None,
            log_entries=(),
            resolved_comment_count=0,
            total_comment_count=0,
            comments_display="-",
            learn_status=None,
            learn_plan_issue=None,
            learn_plan_issue_closed=None,
            learn_plan_pr=None,
            learn_run_url=None,
            learn_display="- not started",
            learn_display_icon="-",
            objective_issue=None,
            objective_display="-",
        )
        executor = FakeCommandExecutor()
        screen = PlanDetailScreen(row=row, executor=executor)
        screen.execute_command("submit_to_queue")
        assert executor.refresh_count == 0


class TestExecuteCommandLandPR:
    """Tests for land_pr command.

    Note: land_pr uses streaming output via subprocess when repo_root is provided
    and pr_number exists. These tests verify the guard conditions but actual
    streaming behavior is tested via integration tests.
    """

    def test_land_pr_does_nothing_without_repo_root(self) -> None:
        """land_pr does nothing if repo_root is not provided."""
        row = make_plan_row(123, "Test", pr_number=456)
        executor = FakeCommandExecutor()
        # repo_root not provided - streaming command should not execute
        screen = PlanDetailScreen(row=row, executor=executor)
        screen.execute_command("land_pr")
        # No executor methods should be called (streaming is independent)
        assert executor.refresh_count == 0

    def test_land_pr_does_nothing_without_pr_number(self) -> None:
        """land_pr does nothing if no PR is associated with the plan."""
        row = make_plan_row(123, "Test")  # No pr_number
        executor = FakeCommandExecutor()
        screen = PlanDetailScreen(row=row, executor=executor, repo_root=Path("/some/path"))
        screen.execute_command("land_pr")
        assert executor.refresh_count == 0


class TestExecuteCommandFixConflictsRemote:
    """Tests for fix_conflicts_remote command.

    Note: fix_conflicts_remote uses streaming output via subprocess when repo_root
    is provided and pr_number exists. These tests verify the guard conditions but
    actual streaming behavior is tested via integration tests.
    """

    def test_fix_conflicts_remote_does_nothing_without_repo_root(self) -> None:
        """fix_conflicts_remote does nothing if repo_root is not provided."""
        row = make_plan_row(123, "Test", pr_number=456)
        executor = FakeCommandExecutor()
        # repo_root not provided - streaming command should not execute
        screen = PlanDetailScreen(row=row, executor=executor)
        screen.execute_command("fix_conflicts_remote")
        # No executor methods should be called (streaming is independent)
        assert executor.refresh_count == 0

    def test_fix_conflicts_remote_does_nothing_without_pr_number(self) -> None:
        """fix_conflicts_remote does nothing if no PR is associated with the plan."""
        row = make_plan_row(123, "Test")  # No pr_number
        executor = FakeCommandExecutor()
        screen = PlanDetailScreen(row=row, executor=executor, repo_root=Path("/some/path"))
        screen.execute_command("fix_conflicts_remote")
        assert executor.refresh_count == 0


class TestExecuteCommandNoExecutor:
    """Tests for behavior when no executor is provided."""

    def test_does_nothing_without_executor(self) -> None:
        """Commands do nothing when no executor is provided."""
        row = make_plan_row(123, "Test")
        screen = PlanDetailScreen(row=row)  # No executor
        # Should not raise
        screen.execute_command("open_browser")
        screen.execute_command("copy_prepare")
        screen.execute_command("close_plan")
        screen.execute_command("submit_to_queue")
        screen.execute_command("land_pr")
        screen.execute_command("fix_conflicts_remote")
