import asyncio
import json
import os
import sys
import tempfile
from typing import Callable

import pytest
from fastmcp import Client

TEST_CONFIG = {
    "enable_umlaut_fixing": True,
    "umlaut_config": {
        "string_mapping": {"Ä": "CAE_UMLT"},
        "comment_mapping": {"Ä": "Ae"},
    },
    "encoding_config": {
        "default": "utf-8",
        "mapping": {"*.cpp": "latin-1", "*.h": "latin-1"},
    },
}


@pytest.fixture(scope="session")
def tmp_dir():
    with tempfile.TemporaryDirectory() as d:
        yield d.replace("\\", "/")


@pytest.fixture(scope="session")
def config_path(tmp_dir: str) -> str:
    path = os.path.join(tmp_dir, "test_config.json")
    with open(path, "w") as f:
        json.dump(TEST_CONFIG, f)
    return path





@pytest.fixture(scope="session")
async def shared_client(tmp_dir: str, config_path: str):
    """Create a single client that lives for the entire test session."""
    print("\n[conftest] Creating fastmcp Client...", flush=True)
    client = Client(
        {
            "mcpServers": {
                "wrapper": {
                    "command": sys.executable,
                    "args": ["-m", "my_mcp"],
                    "env": {
                        **os.environ,
                        "ALLOWED_DIRS": tmp_dir,
                        "SERVER_CONFIG": config_path,
                        "FASTMCP_SHOW_SERVER_BANNER": "false",
                    },
                }
            }
        }
    )
    print("\n[conftest] Entering client...", flush=True)
    await client.__aenter__()
    print("\n[conftest] Client entered!", flush=True)
    yield client
    print("\n[conftest] Exiting client...", flush=True)
    await client.__aexit__(None, None, None)


@pytest.fixture
def client(shared_client):
    """Return the shared client for each test."""
    return shared_client


@pytest.fixture
def tmp_path(tmp_dir: str) -> Callable[[str], str]:
    def _tmp_path(name: str) -> str:
        return os.path.join(tmp_dir, name).replace("\\", "/")

    return _tmp_path


@pytest.fixture
def write_file() -> Callable[[str, str, str], None]:
    def _write_file(path: str, content: str, encoding: str = "utf-8") -> None:
        with open(path, "w", encoding=encoding) as f:
            f.write(content)

    return _write_file


@pytest.fixture
def read_file() -> Callable[[str, str], str]:
    def _read_file(path: str, encoding: str = "utf-8") -> str:
        with open(path, encoding=encoding) as f:
            return f.read()

    return _read_file
