"""Tests for the statusline dispatcher."""

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

import pytest

from statusline.dispatcher import dispatch


class TestDispatch:
    def test_creates_session_dir_and_runs_plugins(self, tmp_path):
        """Dispatcher should create session dir and execute plugins."""
        session_base = tmp_path / "sessions"
        plugin_dir = tmp_path / "plugins"
        plugin_dir.mkdir()

        # Create a simple plugin that writes a marker file
        plugin = plugin_dir / "00-test.py"
        plugin.write_text(
            '#!/usr/bin/env python3\n'
            'import json, os, sys\n'
            'd = json.load(sys.stdin)\n'
            'sd = os.environ["STATUSLINE_SESSION_DIR"]\n'
            'open(os.path.join(sd, "marker"), "w").write("ok")\n'
        )
        plugin.chmod(0o755)

        session_data = {"session_id": "test-123", "transcript_path": "/dev/null"}

        with patch("statusline.dispatcher.PLUGIN_DIR", plugin_dir), \
             patch("statusline.dispatcher.SESSION_BASE", session_base), \
             patch("sys.stdin") as mock_stdin:
            mock_stdin.buffer.read.return_value = json.dumps(session_data).encode()
            dispatch()

        assert (session_base / "test-123").is_dir()
        assert (session_base / "test-123" / "marker").read_text() == "ok"

    def test_skips_non_executable_plugins(self, tmp_path):
        session_base = tmp_path / "sessions"
        plugin_dir = tmp_path / "plugins"
        plugin_dir.mkdir()

        # Create a non-executable plugin
        plugin = plugin_dir / "00-test.py"
        plugin.write_text('#!/usr/bin/env python3\nimport sys\n')
        plugin.chmod(0o644)  # not executable

        session_data = {"session_id": "test-456"}

        with patch("statusline.dispatcher.PLUGIN_DIR", plugin_dir), \
             patch("statusline.dispatcher.SESSION_BASE", session_base), \
             patch("sys.stdin") as mock_stdin:
            mock_stdin.buffer.read.return_value = json.dumps(session_data).encode()
            dispatch()

        # Session dir should exist but no marker
        assert (session_base / "test-456").is_dir()

    def test_handles_invalid_json_gracefully(self, tmp_path):
        """Dispatcher should silently return on invalid JSON input."""
        with patch("sys.stdin") as mock_stdin:
            mock_stdin.buffer.read.return_value = b"not json"
            dispatch()  # Should not raise

    def test_handles_missing_plugin_dir(self, tmp_path):
        """Dispatcher should silently return if plugin dir doesn't exist."""
        session_base = tmp_path / "sessions"
        plugin_dir = tmp_path / "nonexistent"

        session_data = {"session_id": "test-789"}

        with patch("statusline.dispatcher.PLUGIN_DIR", plugin_dir), \
             patch("statusline.dispatcher.SESSION_BASE", session_base), \
             patch("sys.stdin") as mock_stdin:
            mock_stdin.buffer.read.return_value = json.dumps(session_data).encode()
            dispatch()  # Should not raise

    def test_plugin_timeout(self, tmp_path):
        """Plugins that exceed timeout should not block dispatcher."""
        session_base = tmp_path / "sessions"
        plugin_dir = tmp_path / "plugins"
        plugin_dir.mkdir()

        # Create a plugin that sleeps forever
        plugin = plugin_dir / "00-slow.py"
        plugin.write_text(
            '#!/usr/bin/env python3\nimport time, sys, json\n'
            'json.load(sys.stdin)\ntime.sleep(60)\n'
        )
        plugin.chmod(0o755)

        session_data = {"session_id": "test-timeout"}

        with patch("statusline.dispatcher.PLUGIN_DIR", plugin_dir), \
             patch("statusline.dispatcher.SESSION_BASE", session_base), \
             patch("sys.stdin") as mock_stdin:
            mock_stdin.buffer.read.return_value = json.dumps(session_data).encode()
            dispatch()  # Should complete without hanging
