"""Tests for script reload integration in script_ops.py."""

from __future__ import annotations

import os

import pytest
from unittest.mock import AsyncMock, patch

from godotiq.tools.bridge.script_ops import _try_reload_script, _op_write, _op_create


class TestTryReloadScript:
    """Tests for the _try_reload_script helper function."""

    async def test_calls_bridge_reload_for_gd_file(self) -> None:
        mock_bridge = AsyncMock()
        mock_bridge.request.return_value = {"reloaded": True}
        with patch("godotiq.bridge.session.get_bridge_or_none", return_value=mock_bridge):
            await _try_reload_script("scripts/enemy.gd")
        mock_bridge.request.assert_called_once_with(
            "reload_script", params={"path": "res://scripts/enemy.gd"}
        )

    async def test_constructs_correct_res_path(self) -> None:
        mock_bridge = AsyncMock()
        mock_bridge.request.return_value = {"reloaded": True}
        with patch("godotiq.bridge.session.get_bridge_or_none", return_value=mock_bridge):
            await _try_reload_script("scenes/main_controller.gd")
        call_params = mock_bridge.request.call_args[1]["params"]
        assert call_params["path"] == "res://scenes/main_controller.gd"

    async def test_skips_tres_files(self) -> None:
        mock_bridge = AsyncMock()
        with patch("godotiq.bridge.session.get_bridge_or_none", return_value=mock_bridge):
            await _try_reload_script("resources/data.tres")
        mock_bridge.request.assert_not_called()

    async def test_skips_tscn_files(self) -> None:
        mock_bridge = AsyncMock()
        with patch("godotiq.bridge.session.get_bridge_or_none", return_value=mock_bridge):
            await _try_reload_script("scenes/main.tscn")
        mock_bridge.request.assert_not_called()

    async def test_silent_skip_when_bridge_is_none(self) -> None:
        with patch("godotiq.bridge.session.get_bridge_or_none", return_value=None):
            await _try_reload_script("scripts/test.gd")  # Should not raise

    async def test_silent_skip_on_bridge_exception(self) -> None:
        mock_bridge = AsyncMock()
        mock_bridge.request.side_effect = Exception("Connection lost")
        with patch("godotiq.bridge.session.get_bridge_or_none", return_value=mock_bridge):
            await _try_reload_script("scripts/test.gd")  # Should not raise


class TestOpWriteReload:
    """Tests that _op_write triggers reload for .gd files."""

    async def test_op_write_calls_reload_for_gd(self, tmp_path) -> None:
        gd_file = tmp_path / "player.gd"
        gd_file.write_text("extends Node\n")
        rel_path = "player.gd"

        mock_reload = AsyncMock()
        with patch.dict(os.environ, {"GODOTIQ_PROJECT_ROOT": str(tmp_path)}):
            with patch("godotiq.tools.bridge.script_ops._try_reload_script", mock_reload):
                await _op_write(gd_file, rel_path, "extends Node2D\n", [], False)
        mock_reload.assert_awaited_once_with(rel_path)

    async def test_op_write_skips_reload_for_non_gd(self, tmp_path) -> None:
        tres_file = tmp_path / "data.tres"
        tres_file.write_text("[gd_resource]\n")
        rel_path = "data.tres"

        mock_reload = AsyncMock()
        with patch.dict(os.environ, {"GODOTIQ_PROJECT_ROOT": str(tmp_path)}):
            with patch("godotiq.tools.bridge.script_ops._try_reload_script", mock_reload):
                await _op_write(tres_file, rel_path, "[gd_resource]\nfoo=1\n", [], False)
        mock_reload.assert_not_called()


class TestOpCreateReload:
    """Tests that _op_create triggers reload for .gd files."""

    async def test_op_create_calls_reload_for_gd(self, tmp_path) -> None:
        gd_file = tmp_path / "new_script.gd"
        rel_path = "new_script.gd"

        mock_reload = AsyncMock()
        with patch.dict(os.environ, {"GODOTIQ_PROJECT_ROOT": str(tmp_path)}):
            with patch("godotiq.tools.bridge.script_ops._try_reload_script", mock_reload):
                await _op_create(gd_file, rel_path, "extends Node\n")
        mock_reload.assert_awaited_once_with(rel_path)

    async def test_op_create_skips_reload_for_non_gd(self, tmp_path) -> None:
        tres_file = tmp_path / "resource.tres"
        rel_path = "resource.tres"

        mock_reload = AsyncMock()
        with patch.dict(os.environ, {"GODOTIQ_PROJECT_ROOT": str(tmp_path)}):
            with patch("godotiq.tools.bridge.script_ops._try_reload_script", mock_reload):
                await _op_create(tres_file, rel_path, "[gd_resource]\n")
        mock_reload.assert_not_called()
