"""Tests for the process queue module."""

from __future__ import annotations

import asyncio
import sys

import pytest

from elizaos_plugin_shell.process_queue import (
    CommandLane,
    CommandOptions,
    ProcessQueue,
    SpawnResult,
    run_command_with_timeout,
    run_exec,
)


class TestProcessQueue:
    @pytest.mark.asyncio
    async def test_enqueue_single_task(self):
        queue = ProcessQueue()

        async def task():
            return 42

        result = await queue.enqueue(task=task)
        assert result == 42

    @pytest.mark.asyncio
    async def test_enqueue_preserves_order(self):
        queue = ProcessQueue()
        results = []

        async def make_task(n):
            results.append(n)
            return n

        await queue.enqueue(task=lambda: make_task(1))
        await queue.enqueue(task=lambda: make_task(2))
        await queue.enqueue(task=lambda: make_task(3))

        assert results == [1, 2, 3]

    @pytest.mark.asyncio
    async def test_size(self):
        queue = ProcessQueue()
        assert queue.size() == 0
        assert queue.total_size() == 0

    @pytest.mark.asyncio
    async def test_clear(self):
        queue = ProcessQueue()
        cleared = await queue.clear()
        assert cleared == 0

    def test_set_lane_concurrency(self):
        queue = ProcessQueue()
        queue.set_lane_concurrency("main", 4)
        # Should not crash

    def test_command_lane_values(self):
        assert CommandLane.MAIN.value == "main"
        assert CommandLane.CRON.value == "cron"
        assert CommandLane.SUBAGENT.value == "subagent"
        assert CommandLane.NESTED.value == "nested"


class TestSpawnResult:
    def test_spawn_result_creation(self):
        result = SpawnResult(
            stdout="hello",
            stderr="",
            code=0,
            signal=None,
            killed=False,
        )
        assert result.stdout == "hello"
        assert result.code == 0
        assert result.killed is False


class TestCommandOptions:
    def test_default_options(self):
        opts = CommandOptions()
        assert opts.timeout_ms == 10_000
        assert opts.cwd is None
        assert opts.input_data is None

    def test_custom_options(self):
        opts = CommandOptions(
            timeout_ms=5000,
            cwd="/tmp",
            input_data="hello",
            env={"KEY": "value"},
        )
        assert opts.timeout_ms == 5000
        assert opts.cwd == "/tmp"


class TestRunExec:
    @pytest.mark.asyncio
    async def test_run_echo(self):
        if sys.platform == "win32":
            pytest.skip("Unix-only test")
        result = await run_exec("echo", ["hello"])
        assert "hello" in result["stdout"]

    @pytest.mark.asyncio
    async def test_run_nonexistent(self):
        with pytest.raises(FileNotFoundError):
            await run_exec("nonexistent_command_xyz", [])


class TestRunCommandWithTimeout:
    @pytest.mark.asyncio
    async def test_echo_command(self):
        if sys.platform == "win32":
            pytest.skip("Unix-only test")
        result = await run_command_with_timeout(
            ["echo", "hello"],
            CommandOptions(timeout_ms=5000),
        )
        assert result.code == 0
        assert "hello" in result.stdout

    @pytest.mark.asyncio
    async def test_timeout(self):
        if sys.platform == "win32":
            pytest.skip("Unix-only test")
        result = await run_command_with_timeout(
            ["sleep", "10"],
            CommandOptions(timeout_ms=100),
        )
        assert result.killed is True
        assert result.code is None

    @pytest.mark.asyncio
    async def test_with_input(self):
        if sys.platform == "win32":
            pytest.skip("Unix-only test")
        result = await run_command_with_timeout(
            ["cat"],
            CommandOptions(timeout_ms=5000, input_data="hello from stdin"),
        )
        assert result.code == 0
        assert "hello from stdin" in result.stdout

    @pytest.mark.asyncio
    async def test_command_not_found(self):
        result = await run_command_with_timeout(
            ["nonexistent_command_xyz"],
            CommandOptions(timeout_ms=5000),
        )
        assert result.code == 127 or result.code == 1

    @pytest.mark.asyncio
    async def test_with_cwd(self):
        if sys.platform == "win32":
            pytest.skip("Unix-only test")
        result = await run_command_with_timeout(
            ["pwd"],
            CommandOptions(timeout_ms=5000, cwd="/tmp"),
        )
        assert result.code == 0
        # /tmp may resolve to /private/tmp on macOS
        assert "tmp" in result.stdout
