"""Tests for tmux operations.

Note: These tests require a running tmux server and create real sessions.
They clean up after themselves but may leave orphaned sessions if tests fail.
"""

import contextlib
import uuid

import pytest

from legionnaire.tmux_ops import (
    CHILD_PALETTE,
    LEGION_WSTYLE_OPTION,
    PARENT_RED,
    SessionNotManagedError,
    apply_colors,
    ensure_child_window,
    ensure_managed_session,
    ensure_parent_window,
    get_server,
    get_session,
    is_session_managed,
    kill_window,
    list_child_windows,
    reorder_windows,
    session_exists,
)


@pytest.fixture
def unique_session_name():
    """Generate a unique session name for testing."""
    return f"legion-test-{uuid.uuid4().hex[:8]}"


@pytest.fixture
def managed_session(unique_session_name, tmp_path):
    """Create a managed session for testing."""
    session = ensure_managed_session(unique_session_name, tmp_path)
    yield session
    # Cleanup
    with contextlib.suppress(Exception):
        session.kill()


class TestSessionExists:
    """Tests for session_exists function."""

    def test_nonexistent_session(self, unique_session_name):
        assert session_exists(unique_session_name) is False

    def test_existing_session(self, managed_session):
        assert session_exists(managed_session.name) is True


class TestIsSessionManaged:
    """Tests for is_session_managed function."""

    def test_managed_session(self, managed_session):
        assert is_session_managed(managed_session) is True

    def test_unmanaged_session(self, unique_session_name, tmp_path):
        server = get_server()
        session = server.new_session(
            session_name=unique_session_name,
            start_directory=str(tmp_path),
            attach=False,
        )
        try:
            assert is_session_managed(session) is False
        finally:
            session.kill()


class TestEnsureManagedSession:
    """Tests for ensure_managed_session function."""

    def test_creates_new_session(self, unique_session_name, tmp_path):
        session = ensure_managed_session(unique_session_name, tmp_path)
        try:
            assert session.name == unique_session_name
            assert is_session_managed(session) is True
        finally:
            session.kill()

    def test_returns_existing_managed_session(self, managed_session, tmp_path):
        session = ensure_managed_session(managed_session.name, tmp_path)
        assert session.id == managed_session.id

    def test_raises_for_unmanaged_session(self, unique_session_name, tmp_path):
        server = get_server()
        session = server.new_session(
            session_name=unique_session_name,
            start_directory=str(tmp_path),
            attach=False,
        )
        try:
            with pytest.raises(SessionNotManagedError):
                ensure_managed_session(unique_session_name, tmp_path)
        finally:
            session.kill()


class TestEnsureParentWindow:
    """Tests for ensure_parent_window function."""

    def test_renames_first_window(self, managed_session, tmp_path):
        window = ensure_parent_window(managed_session, tmp_path)
        assert window.name == "parent"

    def test_sets_parent_color(self, managed_session, tmp_path):
        window = ensure_parent_window(managed_session, tmp_path)
        style = window.show_option(LEGION_WSTYLE_OPTION)
        assert PARENT_RED in style


class TestEnsureChildWindow:
    """Tests for ensure_child_window function."""

    def test_creates_new_window(self, managed_session, tmp_path):
        window = ensure_child_window(managed_session, "child-1", tmp_path)
        assert window.name == "child-1"

    def test_creates_window_in_correct_directory(self, managed_session, tmp_path):
        """Verify the window's pane starts in the specified directory."""
        child_dir = tmp_path / "child-worktree"
        child_dir.mkdir()

        window = ensure_child_window(managed_session, "child-1", child_dir)

        # Verify the pane's current path is the child directory
        pane = window.panes[0]
        # pane_current_path may have /private prefix on macOS
        assert str(child_dir) in pane.pane_current_path or pane.pane_current_path.endswith(
            str(child_dir.name)
        )

    def test_returns_existing_window(self, managed_session, tmp_path):
        window1 = ensure_child_window(managed_session, "child-1", tmp_path)
        window2 = ensure_child_window(managed_session, "child-1", tmp_path)
        assert window1.id == window2.id


class TestListChildWindows:
    """Tests for list_child_windows function."""

    def test_excludes_parent(self, managed_session, tmp_path):
        ensure_parent_window(managed_session, tmp_path)
        children = list_child_windows(managed_session)
        assert "parent" not in children

    def test_lists_all_children(self, managed_session, tmp_path):
        ensure_parent_window(managed_session, tmp_path)
        ensure_child_window(managed_session, "child-a", tmp_path)
        ensure_child_window(managed_session, "child-b", tmp_path)

        children = list_child_windows(managed_session)
        assert children == {"child-a", "child-b"}


class TestKillWindow:
    """Tests for kill_window function."""

    def test_kills_existing_window(self, managed_session, tmp_path):
        ensure_child_window(managed_session, "to-kill", tmp_path)
        result = kill_window(managed_session, "to-kill")

        assert result is True
        assert "to-kill" not in list_child_windows(managed_session)

    def test_returns_false_for_missing(self, managed_session):
        result = kill_window(managed_session, "nonexistent")
        assert result is False


class TestReorderWindows:
    """Tests for reorder_windows function."""

    def test_reorders_children(self, managed_session, tmp_path):
        ensure_parent_window(managed_session, tmp_path)
        ensure_child_window(managed_session, "zeta", tmp_path)
        ensure_child_window(managed_session, "alpha", tmp_path)
        ensure_child_window(managed_session, "beta", tmp_path)

        reorder_windows(managed_session, ["alpha", "beta", "zeta"])

        # Refresh windows
        windows = managed_session.windows
        assert windows[0].name == "parent"
        assert windows[1].name == "alpha"
        assert windows[2].name == "beta"
        assert windows[3].name == "zeta"


class TestApplyColors:
    """Tests for apply_colors function."""

    def test_applies_parent_color(self, managed_session, tmp_path):
        ensure_parent_window(managed_session, tmp_path)
        apply_colors(managed_session, [])

        parent = managed_session.windows[0]
        style = parent.show_option(LEGION_WSTYLE_OPTION)
        assert PARENT_RED in style

    def test_applies_child_colors_in_order(self, managed_session, tmp_path):
        ensure_parent_window(managed_session, tmp_path)
        ensure_child_window(managed_session, "alpha", tmp_path)
        ensure_child_window(managed_session, "beta", tmp_path)

        apply_colors(managed_session, ["alpha", "beta"])

        alpha_style = None
        beta_style = None
        for w in managed_session.windows:
            if w.name == "alpha":
                alpha_style = w.show_option(LEGION_WSTYLE_OPTION)
            elif w.name == "beta":
                beta_style = w.show_option(LEGION_WSTYLE_OPTION)

        assert CHILD_PALETTE[0] in alpha_style
        assert CHILD_PALETTE[1] in beta_style


class TestGetSession:
    """Tests for get_session function."""

    def test_returns_session(self, managed_session):
        session = get_session(managed_session.name)
        assert session is not None
        assert session.id == managed_session.id

    def test_returns_none_for_missing(self, unique_session_name):
        session = get_session(unique_session_name)
        assert session is None
