"""Tests for script rename with reference update in file_ops."""

from __future__ import annotations

import os
import pytest

from godotiq.tools.bridge.file_ops import _op_rename


def _create_project(tmp_path):
    """Create a minimal project structure for testing."""
    (tmp_path / "scripts").mkdir()
    (tmp_path / "scenes").mkdir()

    (tmp_path / "scripts" / "old_name.gd").write_text(
        "class_name OldName\nextends Node\n"
    )

    (tmp_path / "scenes" / "main.tscn").write_text(
        '[gd_scene format=3]\n'
        '[ext_resource type="Script" path="res://scripts/old_name.gd" id="1"]\n'
        '[node name="Main" type="Node"]\nscript = ExtResource("1")\n'
    )

    (tmp_path / "scripts" / "other.gd").write_text(
        'var helper = preload("res://scripts/old_name.gd")\n'
    )

    (tmp_path / "project.godot").write_text(
        '[autoload]\nOldName="*res://scripts/old_name.gd"\n'
    )


class TestScriptRename:
    def test_rename_updates_tscn(self, tmp_path, monkeypatch):
        """After rename, .tscn should reference new path."""
        _create_project(tmp_path)
        monkeypatch.setenv("GODOTIQ_PROJECT_ROOT", str(tmp_path))

        result = _op_rename(
            "res://scripts/old_name.gd",
            "res://scripts/new_name.gd",
            "",
        )
        assert result["renamed"] is True
        content = (tmp_path / "scenes" / "main.tscn").read_text()
        assert "res://scripts/new_name.gd" in content
        assert "res://scripts/old_name.gd" not in content

    def test_rename_updates_gd(self, tmp_path, monkeypatch):
        """After rename, other .gd files should reference new path."""
        _create_project(tmp_path)
        monkeypatch.setenv("GODOTIQ_PROJECT_ROOT", str(tmp_path))

        _op_rename("res://scripts/old_name.gd", "res://scripts/new_name.gd", "")
        content = (tmp_path / "scripts" / "other.gd").read_text()
        assert "res://scripts/new_name.gd" in content
        assert "res://scripts/old_name.gd" not in content

    def test_rename_moves_file(self, tmp_path, monkeypatch):
        """After rename, old file gone, new file exists."""
        _create_project(tmp_path)
        monkeypatch.setenv("GODOTIQ_PROJECT_ROOT", str(tmp_path))

        _op_rename("res://scripts/old_name.gd", "res://scripts/new_name.gd", "")
        assert not (tmp_path / "scripts" / "old_name.gd").exists()
        assert (tmp_path / "scripts" / "new_name.gd").exists()

    def test_rename_moves_uid_file(self, tmp_path, monkeypatch):
        """If .uid file exists, it should be renamed too."""
        _create_project(tmp_path)
        (tmp_path / "scripts" / "old_name.gd.uid").write_text("uid://test123\n")
        monkeypatch.setenv("GODOTIQ_PROJECT_ROOT", str(tmp_path))

        _op_rename("res://scripts/old_name.gd", "res://scripts/new_name.gd", "")
        assert not (tmp_path / "scripts" / "old_name.gd.uid").exists()
        assert (tmp_path / "scripts" / "new_name.gd.uid").exists()

    def test_rename_protected_file_blocked(self, tmp_path, monkeypatch):
        """Renaming project.godot should be blocked."""
        (tmp_path / "project.godot").write_text("[config]\n")
        monkeypatch.setenv("GODOTIQ_PROJECT_ROOT", str(tmp_path))

        result = _op_rename("project.godot", "old_project.godot", "")
        assert "error" in result
        assert "protected" in result["error"].lower()

    def test_rename_without_reference_update(self, tmp_path, monkeypatch):
        """update_references=False should only move the file."""
        _create_project(tmp_path)
        monkeypatch.setenv("GODOTIQ_PROJECT_ROOT", str(tmp_path))

        result = _op_rename(
            "res://scripts/old_name.gd",
            "res://scripts/new_name.gd",
            "false",
        )
        assert result["renamed"] is True
        assert result["references_updated"] == 0
        # File moved
        assert (tmp_path / "scripts" / "new_name.gd").exists()
        # References NOT updated
        content = (tmp_path / "scenes" / "main.tscn").read_text()
        assert "res://scripts/old_name.gd" in content

    def test_rename_file_not_found(self, tmp_path, monkeypatch):
        """Renaming nonexistent file should error."""
        monkeypatch.setenv("GODOTIQ_PROJECT_ROOT", str(tmp_path))

        result = _op_rename("res://nonexistent.gd", "res://new.gd", "")
        assert "error" in result

    def test_rename_returns_updated_files(self, tmp_path, monkeypatch):
        """Should return list of files that had references updated."""
        _create_project(tmp_path)
        monkeypatch.setenv("GODOTIQ_PROJECT_ROOT", str(tmp_path))

        result = _op_rename("res://scripts/old_name.gd", "res://scripts/new_name.gd", "")
        assert result["references_updated"] >= 2  # main.tscn + other.gd
        assert any("main.tscn" in f for f in result["updated_files"])
        assert any("other.gd" in f for f in result["updated_files"])

    def test_rename_creates_subdirectory(self, tmp_path, monkeypatch):
        """Rename to a new subdirectory should create it."""
        _create_project(tmp_path)
        monkeypatch.setenv("GODOTIQ_PROJECT_ROOT", str(tmp_path))

        result = _op_rename(
            "res://scripts/old_name.gd",
            "res://scripts/managers/new_name.gd",
            "",
        )
        assert result["renamed"] is True
        assert (tmp_path / "scripts" / "managers" / "new_name.gd").exists()

    def test_rename_missing_paths(self):
        """Missing path or destination should error."""
        result = _op_rename("", "res://new.gd", "")
        assert "error" in result
        result = _op_rename("res://old.gd", "", "")
        assert "error" in result
