import contextlib
import gc
from pathlib import Path

import pytest

from mcp_agent_mail.config import clear_settings_cache
from mcp_agent_mail.db import reset_database_state


@pytest.fixture
def isolated_env(tmp_path, monkeypatch):
    """Provide isolated database settings for tests and reset caches."""
    db_path: Path = tmp_path / "test.sqlite3"
    monkeypatch.setenv("DATABASE_URL", f"sqlite+aiosqlite:///{db_path}")
    monkeypatch.setenv("HTTP_HOST", "127.0.0.1")
    monkeypatch.setenv("HTTP_PORT", "8765")
    monkeypatch.setenv("HTTP_PATH", "/mcp/")
    monkeypatch.setenv("APP_ENVIRONMENT", "test")
    monkeypatch.setenv("MCP_TOOLS_MODE", "extended")
    storage_root = tmp_path / "storage"
    monkeypatch.setenv("STORAGE_ROOT", str(storage_root))
    monkeypatch.setenv("GIT_AUTHOR_NAME", "test-agent")
    monkeypatch.setenv("GIT_AUTHOR_EMAIL", "test@example.com")
    monkeypatch.setenv("INLINE_IMAGE_MAX_BYTES", "128")
    clear_settings_cache()
    reset_database_state()
    try:
        yield
    finally:
        # Close any Git Repo objects before cleanup to prevent subprocess warnings
        # Suppress ResourceWarnings during cleanup since Python 3.14 warns about resources
        # being cleaned up by GC, which is exactly what we want
        import warnings
        with warnings.catch_warnings():
            warnings.filterwarnings("ignore", category=ResourceWarning)
            try:
                import time

                from git import Repo

                # Explicitly close repo at storage_root if it exists
                storage_root = tmp_path / "storage"
                if storage_root.exists() and (storage_root / ".git").exists():
                    try:
                        repo = Repo(str(storage_root))
                        repo.close()
                        del repo
                    except Exception:
                        pass

                # Multiple GC passes to ensure full cleanup
                for _ in range(3):
                    gc.collect()
                    # Close any Repo instances that might still be open
                    for obj in gc.get_objects():
                        if isinstance(obj, Repo):
                            with contextlib.suppress(Exception):
                                obj.close()

                # Give subprocesses time to terminate
                time.sleep(0.1)

                # Final GC pass
                gc.collect()
            except Exception:
                pass

            # Force another GC to clean up any remaining references (inside warning suppression)
            gc.collect()

        clear_settings_cache()
        reset_database_state()

        if db_path.exists():
            db_path.unlink()
        storage_root = tmp_path / "storage"
        if storage_root.exists():
            for path in storage_root.rglob("*"):
                if path.is_file():
                    path.unlink()
            for path in sorted(storage_root.rglob("*"), reverse=True):
                if path.is_dir():
                    path.rmdir()
            if storage_root.exists():
                storage_root.rmdir()
