import os
import tempfile
from contextlib import contextmanager
from typing import Optional

from fastmcp import FastMCP, Context
from fastmcp.server.lifespan import lifespan

from my_mcp import filesystem_server
from my_mcp.server_config import ServerConfig
from my_mcp.umlaut_fixer import fix_document

ALLOWED_DIRS = os.environ.get("ALLOWED_DIRS", os.getcwd()).split(os.pathsep)
SERVER_CONFIG_PATH = os.environ.get("SERVER_CONFIG", "server_config.json")


@contextmanager
def utf8_temp(content: str):
    """Write content to a UTF-8 temp file, yield its path, then clean up."""
    with tempfile.NamedTemporaryFile(mode="w", suffix=".txt", encoding="utf-8", delete=False) as tmp:
        tmp.write(content)
        tmp_path = tmp.name
    try:
        yield tmp_path
    finally:
        os.unlink(tmp_path)


@lifespan
async def manage_backend(server):
    config = ServerConfig.from_path(SERVER_CONFIG_PATH)
    client = filesystem_server.create_client(ALLOWED_DIRS)
    async with client:
        yield {"backend": client, "config": config}


mcp = FastMCP("filesystem-edit-mcp", lifespan=manage_backend)


@mcp.tool
async def read_text_file(
    path: str,
    head: Optional[int] = None,
    tail: Optional[int] = None,
    ctx: Context | None = None,
) -> str:
    """Read complete contents of a file as text.
    Reads the source file in the configured encoding.
    Cannot specify both head and tail simultaneously."""
    assert ctx is not None
    backend = ctx.lifespan_context["backend"]
    encoding = ctx.lifespan_context["config"].encoding_for(path)

    with open(path, encoding=encoding) as f:
        content = f.read()

    with utf8_temp(content) as tmp_path:
        args = {"path": tmp_path}
        if head is not None:
            args["head"] = head
        if tail is not None:
            args["tail"] = tail
        result = await backend.call_tool("read_text_file", args)

    return result.content[0].text if result.content else ""


@mcp.tool
async def edit_file(
    path: str,
    edits: list[dict],
    dryRun: bool = False,
    ctx: Context | None = None,
) -> str:
    """Edit a file using advanced pattern matching and formatting.
    Reads the file in the configured encoding, converts to UTF-8 for editing,
    then converts back. Applies umlaut fixing at the end.
    Use dryRun=True to preview changes before applying."""
    assert ctx is not None
    backend = ctx.lifespan_context["backend"]
    config = ctx.lifespan_context["config"]
    encoding = config.encoding_for(path)

    with open(path, encoding=encoding) as f:
        content = f.read()

    with utf8_temp(content) as tmp_path:
        result = await backend.call_tool(filesystem_server.TOOL_NAME, {
            "path": tmp_path,
            "edits": edits,
            "dryRun": dryRun,
        })

        if not dryRun:
            with open(tmp_path, encoding="utf-8") as f:
                edited = f.read()
            fixed = fix_document(edited, config.umlaut_config)
            with open(path, "w", encoding=encoding) as f:
                f.write(fixed)

    return result.content[0].text if result.content else ""


def main() -> None:
    mcp.run(transport="stdio")


if __name__ == "__main__":
    main()
