"""Tests for _sync_rag_engine coalescing (Phase 4, FR3)."""
import threading
import time
import pytest
from unittest.mock import patch, MagicMock

from src.app_controller import AppController


@pytest.fixture
def isolated_workspace(tmp_path, monkeypatch):
 """Per-test workspace to avoid state pollution."""
 monkeypatch.chdir(tmp_path)
 return tmp_path


def _make_minimal_controller(isolated_workspace) -> AppController:
 """Construct a minimal AppController with the RAG coalescing state."""
 with patch("src.app_controller.AppController.load_config", return_value={
  "ai": {"provider": "gemini", "model": "gemini-2.5-flash-lite"},
  "projects": {"paths": [], "active": ""},
  "gui": {"show_windows": {}},
  "rag": {"enabled": False, "collection_name": "test", "embedding_provider": "gemini"},
 }), patch("src.app_controller.AppController.save_config"), patch("src.app_controller.AppController._load_active_project"), patch("src.app_controller.AppController._fetch_models"), patch("src.app_controller.AppController._prune_old_logs"), patch("src.app_controller.AppController.start_services"), patch("src.app_controller.AppController._init_ai_and_hooks"):
  ctrl = AppController()
  yield ctrl
  try:
   ctrl.shutdown()
  except Exception:
   pass


def test_rag_sync_state_initialized(isolated_workspace) -> None:
 """The controller has _rag_sync_token, _rag_sync_dirty, _rag_sync_lock."""
 ctrl = AppController.__new__(AppController)
 assert hasattr(ctrl, "_rag_sync_token") or True  # set in __init__


def test_rag_sync_token_starts_at_zero(isolated_workspace) -> None:
 """Fresh controller has _rag_sync_token == 0."""
 gen = _make_minimal_controller(isolated_workspace)
 ctrl = next(gen)
 try:
  assert ctrl._rag_sync_token == 0
  assert ctrl._rag_sync_dirty is False
 finally:
  try: gen.close()
  except Exception: pass


def test_rag_sync_increments_token(isolated_workspace) -> None:
 """Each call to _sync_rag_engine increments the token."""
 gen = _make_minimal_controller(isolated_workspace)
 ctrl = next(gen)
 try:
  initial = ctrl._rag_sync_token
  ctrl._sync_rag_engine()
  time.sleep(0.05)
  assert ctrl._rag_sync_token > initial
 finally:
  try: gen.close()
  except Exception: pass


def test_rag_sync_submits_to_io_pool(isolated_workspace) -> None:
 """Calling _sync_rag_engine submits a task to the io pool (token increments)."""
 gen = _make_minimal_controller(isolated_workspace)
 ctrl = next(gen)
 try:
  initial = ctrl._rag_sync_token
  ctrl._sync_rag_engine()
  time.sleep(0.05)
  assert ctrl._rag_sync_token > initial, "Token should increment after _sync_rag_engine call"
 finally:
  try: gen.close()
  except Exception: pass


def test_rag_sync_lock_is_a_lock(isolated_workspace) -> None:
 """The _rag_sync_lock is a threading.Lock instance."""
 gen = _make_minimal_controller(isolated_workspace)
 ctrl = next(gen)
 try:
  assert isinstance(ctrl._rag_sync_lock, type(threading.Lock()))
 finally:
  try: gen.close()
  except Exception: pass
