"""Tests for statusline widget renderers and providers."""

from __future__ import annotations

import json
from pathlib import Path
from unittest.mock import patch


class TestModeWidget:
    """Tests for mode_widget()."""

    def test_quick_mode_uppercased(self) -> None:
        from launcher.statusline.widgets import mode_widget

        assert mode_widget("quick") == "[QUICK]"

    def test_spec_mode_uppercased(self) -> None:
        from launcher.statusline.widgets import mode_widget

        assert mode_widget("spec") == "[SPEC]"

    def test_already_uppercase(self) -> None:
        from launcher.statusline.widgets import mode_widget

        assert mode_widget("QUICK") == "[QUICK]"

    def test_custom_mode(self) -> None:
        from launcher.statusline.widgets import mode_widget

        assert mode_widget("dev") == "[DEV]"

    def test_empty_mode(self) -> None:
        from launcher.statusline.widgets import mode_widget

        assert mode_widget("") == "[]"


class TestSessionWidget:
    """Tests for session_widget()."""

    def test_none_session_shows_no_session(self) -> None:
        from launcher.statusline.widgets import session_widget

        assert session_widget(None) == "[no session]"

    def test_shows_truncated_id(self) -> None:
        from launcher.statusline.widgets import session_widget

        session_info = {"id": "abcdef1234567890"}
        result = session_widget(session_info)
        assert "session:" in result
        assert "abcdef12" in result  # first 8 chars

    def test_id_truncated_to_8_chars(self) -> None:
        from launcher.statusline.widgets import session_widget

        session_info = {"id": "1234567890abcdef"}
        result = session_widget(session_info)
        # Should only show first 8 chars
        assert "12345678" in result
        assert "90abcdef" not in result

    def test_missing_id_shows_question_marks(self) -> None:
        from launcher.statusline.widgets import session_widget

        result = session_widget({})
        assert "???" in result

    def test_extra_fields_ignored(self) -> None:
        from launcher.statusline.widgets import session_widget

        session_info = {"id": "abc12345xyz67890", "started_at": "2025-01-01", "ended_at": None}
        result = session_widget(session_info)
        assert "session:" in result
        assert "abc12345" in result


class TestMemoryWidget:
    """Tests for memory_widget()."""

    def test_zero_memories(self) -> None:
        from launcher.statusline.widgets import memory_widget

        assert memory_widget(0) == "[mem:0]"

    def test_positive_count(self) -> None:
        from launcher.statusline.widgets import memory_widget

        assert memory_widget(42) == "[mem:42]"

    def test_large_count(self) -> None:
        from launcher.statusline.widgets import memory_widget

        assert memory_widget(1000) == "[mem:1000]"


class TestGetMode:
    """Tests for providers.get_mode()."""

    def test_returns_mode_from_config(self, tmp_path: Path) -> None:
        home = tmp_path / ".tribunal"
        home.mkdir()
        (home / "config.json").write_text(json.dumps({"mode": "spec"}))

        with patch.dict("os.environ", {"SKILLFIELD_HOME": str(home)}):
            from launcher.statusline.providers import get_mode

            result = get_mode()

        assert result == "spec"

    def test_defaults_to_quick(self, tmp_path: Path) -> None:
        home = tmp_path / ".tribunal"
        home.mkdir()
        # Config with no mode key
        (home / "config.json").write_text(json.dumps({}))

        with patch.dict("os.environ", {"SKILLFIELD_HOME": str(home)}):
            from launcher.statusline.providers import get_mode

            result = get_mode()

        assert result == "quick"

    def test_returns_string(self, tmp_path: Path) -> None:
        home = tmp_path / ".tribunal"
        home.mkdir()
        (home / "config.json").write_text(json.dumps({"mode": "quick"}))

        with patch.dict("os.environ", {"SKILLFIELD_HOME": str(home)}):
            from launcher.statusline.providers import get_mode

            result = get_mode()

        assert isinstance(result, str)


class TestGetMemoryCount:
    """Tests for providers.get_memory_count()."""

    def test_counts_files_in_memory_dir(self, tmp_path: Path) -> None:
        home = tmp_path / ".tribunal"
        home.mkdir()
        memory_dir = home / "memory"
        memory_dir.mkdir()
        (memory_dir / "obs1.md").write_text("obs1")
        (memory_dir / "obs2.md").write_text("obs2")
        (memory_dir / "obs3.md").write_text("obs3")

        with patch.dict("os.environ", {"SKILLFIELD_HOME": str(home)}):
            from launcher.statusline.providers import get_memory_count

            count = get_memory_count()

        assert count == 3

    def test_returns_zero_for_empty_dir(self, tmp_path: Path) -> None:
        home = tmp_path / ".tribunal"
        home.mkdir()
        (home / "memory").mkdir()

        with patch.dict("os.environ", {"SKILLFIELD_HOME": str(home)}):
            from launcher.statusline.providers import get_memory_count

            count = get_memory_count()

        assert count == 0

    def test_returns_zero_on_oserror(self, tmp_path: Path) -> None:
        home = tmp_path / ".tribunal"
        home.mkdir()

        with patch.dict("os.environ", {"SKILLFIELD_HOME": str(home)}):
            with patch("launcher.statusline.providers.get_memory_dir") as mock_dir:
                mock_dir.return_value = tmp_path / "nonexistent" / "memory"
                from launcher.statusline.providers import get_memory_count

                count = get_memory_count()

        assert count == 0

    def test_skips_subdirectories(self, tmp_path: Path) -> None:
        home = tmp_path / ".tribunal"
        home.mkdir()
        memory_dir = home / "memory"
        memory_dir.mkdir()
        (memory_dir / "obs1.md").write_text("obs1")
        subdir = memory_dir / "subdir"
        subdir.mkdir()

        with patch.dict("os.environ", {"SKILLFIELD_HOME": str(home)}):
            from launcher.statusline.providers import get_memory_count

            count = get_memory_count()

        assert count == 1  # Only the file, not the subdir


class TestGetSessionInfo:
    """Tests for providers.get_session_info()."""

    def test_returns_none_when_no_sessions(self, tmp_path: Path) -> None:
        home = tmp_path / ".tribunal"
        home.mkdir()
        (home / "sessions").mkdir()

        with patch.dict("os.environ", {"SKILLFIELD_HOME": str(home)}):
            from launcher.statusline.providers import get_session_info

            result = get_session_info()

        assert result is None

    def test_returns_active_session(self, tmp_path: Path) -> None:
        home = tmp_path / ".tribunal"
        home.mkdir()
        sessions_dir = home / "sessions"
        sessions_dir.mkdir()
        session_file = sessions_dir / "abc123.json"
        session_file.write_text(
            json.dumps({"id": "abc123", "started_at": "2025-01-01T00:00:00+00:00", "ended_at": None})
        )

        with patch.dict("os.environ", {"SKILLFIELD_HOME": str(home)}):
            from launcher.statusline.providers import get_session_info

            result = get_session_info()

        assert result is not None
        assert result["id"] == "abc123"


class TestRenderStatusline:
    """Tests for formatter.render_statusline()."""

    def test_returns_string(self, tmp_path: Path) -> None:
        home = tmp_path / ".tribunal"
        home.mkdir()
        (home / "config.json").write_text(json.dumps({"mode": "quick"}))
        (home / "memory").mkdir()
        (home / "sessions").mkdir()

        with patch.dict("os.environ", {"SKILLFIELD_HOME": str(home)}):
            with patch("sys.stdin") as mock_stdin:
                mock_stdin.isatty.return_value = True
                from launcher.statusline.formatter import render_statusline

                result = render_statusline()

        assert isinstance(result, str)
        assert "[QUICK]" in result

    def test_includes_context_when_available(self, tmp_path: Path) -> None:
        home = tmp_path / ".tribunal"
        home.mkdir()
        (home / "config.json").write_text(json.dumps({"mode": "quick"}))
        (home / "memory").mkdir()
        (home / "sessions").mkdir()

        stdin_data = json.dumps({"context_window": {"used_percentage": 65}})

        with patch.dict("os.environ", {"SKILLFIELD_HOME": str(home), "SF_SESSION_ID": "test-render"}):
            with patch("sys.stdin") as mock_stdin:
                mock_stdin.isatty.return_value = False
                mock_stdin.read.return_value = stdin_data
                from launcher.statusline.formatter import render_statusline

                result = render_statusline()

        assert "[ctx:65%]" in result

    def test_excludes_empty_context_widget(self, tmp_path: Path) -> None:
        home = tmp_path / ".tribunal"
        home.mkdir()
        (home / "config.json").write_text(json.dumps({"mode": "quick"}))
        (home / "memory").mkdir()
        (home / "sessions").mkdir()

        with patch.dict("os.environ", {"SKILLFIELD_HOME": str(home)}):
            with patch("sys.stdin") as mock_stdin:
                mock_stdin.isatty.return_value = True
                from launcher.statusline.formatter import render_statusline

                result = render_statusline()

        # When context is None, context_widget returns "" and should be excluded
        assert "ctx" not in result

    def test_includes_memory_count(self, tmp_path: Path) -> None:
        home = tmp_path / ".tribunal"
        home.mkdir()
        (home / "config.json").write_text(json.dumps({"mode": "quick"}))
        memory_dir = home / "memory"
        memory_dir.mkdir()
        (memory_dir / "entry1.md").write_text("entry")
        (home / "sessions").mkdir()

        with patch.dict("os.environ", {"SKILLFIELD_HOME": str(home)}):
            with patch("sys.stdin") as mock_stdin:
                mock_stdin.isatty.return_value = True
                from launcher.statusline.formatter import render_statusline

                result = render_statusline()

        assert "[mem:1]" in result

    def test_parts_separated_by_spaces(self, tmp_path: Path) -> None:
        home = tmp_path / ".tribunal"
        home.mkdir()
        (home / "config.json").write_text(json.dumps({"mode": "quick"}))
        (home / "memory").mkdir()
        (home / "sessions").mkdir()

        with patch.dict("os.environ", {"SKILLFIELD_HOME": str(home)}):
            with patch("sys.stdin") as mock_stdin:
                mock_stdin.isatty.return_value = True
                from launcher.statusline.formatter import render_statusline

                result = render_statusline()

        # No double spaces (all parts joined with single space)
        assert "  " not in result
