"""Tests for adaptive timeout in run.py."""

from __future__ import annotations

import os

import pytest
from unittest.mock import AsyncMock, patch

from godotiq.tools.bridge.run import run, _compute_timeout


class TestComputeTimeout:
    """Tests for the _compute_timeout helper."""

    def test_zero_glb_gives_10s(self, tmp_path) -> None:
        with patch.dict(os.environ, {"GODOTIQ_PROJECT_ROOT": str(tmp_path)}):
            assert _compute_timeout(0) == 10.0

    def test_60_glb_gives_15s(self, tmp_path) -> None:
        for i in range(60):
            (tmp_path / f"asset_{i}.glb").touch()
        with patch.dict(os.environ, {"GODOTIQ_PROJECT_ROOT": str(tmp_path)}):
            assert _compute_timeout(0) == 15.0

    def test_120_glb_gives_20s(self, tmp_path) -> None:
        subdir = tmp_path / "models"
        subdir.mkdir()
        for i in range(120):
            (subdir / f"building_{i}.glb").touch()
        with patch.dict(os.environ, {"GODOTIQ_PROJECT_ROOT": str(tmp_path)}):
            assert _compute_timeout(0) == 20.0

    def test_explicit_timeout_overrides(self) -> None:
        assert _compute_timeout(30.0) == 30.0

    def test_missing_env_var_gives_15s(self) -> None:
        env = os.environ.copy()
        env.pop("GODOTIQ_PROJECT_ROOT", None)
        with patch.dict(os.environ, env, clear=True):
            assert _compute_timeout(0) == 15.0


class TestRunAdaptiveTimeout:
    """Tests for run() timeout coordination."""

    async def test_bridge_receives_timeout_in_params(self, tmp_path) -> None:
        mock_bridge = AsyncMock()
        mock_bridge.request.return_value = {
            "action": "play", "success": True, "scene": "res://main.tscn", "waited_seconds": 1.0,
        }
        with patch.dict(os.environ, {"GODOTIQ_PROJECT_ROOT": str(tmp_path)}):
            with patch("godotiq.tools.bridge.run.get_bridge", return_value=mock_bridge):
                await run(action="play", scene="main")

        call_kwargs = mock_bridge.request.call_args
        assert call_kwargs[1]["params"]["timeout"] == 10.0  # 0 GLBs → 10s

    async def test_bridge_receives_timeout_kwarg_plus_5(self, tmp_path) -> None:
        mock_bridge = AsyncMock()
        mock_bridge.request.return_value = {
            "action": "play", "success": True, "scene": "res://main.tscn", "waited_seconds": 1.0,
        }
        with patch.dict(os.environ, {"GODOTIQ_PROJECT_ROOT": str(tmp_path)}):
            with patch("godotiq.tools.bridge.run.get_bridge", return_value=mock_bridge):
                await run(action="play", scene="main")

        call_kwargs = mock_bridge.request.call_args
        assert call_kwargs[1]["timeout"] == 15.0  # 10.0 + 5

    async def test_explicit_timeout_overrides_auto(self) -> None:
        mock_bridge = AsyncMock()
        mock_bridge.request.return_value = {
            "action": "play", "success": True, "scene": "res://main.tscn", "waited_seconds": 1.0,
        }
        with patch("godotiq.tools.bridge.run.get_bridge", return_value=mock_bridge):
            await run(action="play", scene="main", timeout=30.0)

        call_kwargs = mock_bridge.request.call_args
        assert call_kwargs[1]["params"]["timeout"] == 30.0
        assert call_kwargs[1]["timeout"] == 35.0

    async def test_stop_does_not_compute_timeout(self) -> None:
        mock_bridge = AsyncMock()
        mock_bridge.request.return_value = {"stopped": True}
        with patch("godotiq.tools.bridge.run.get_bridge", return_value=mock_bridge):
            result = await run(action="stop")

        mock_bridge.request.assert_called_once_with("stop")
        assert result == {"action": "stop"}
