"""Filesystem tools."""

from __future__ import annotations

from pathlib import Path
from typing import Any

from memnixa.tools.base import Tool, paginate_items, paginate_text


class ListDirTool(Tool):
    name = "list_dir"
    description = "List files and directories under a relative path with pagination."
    parameters = {
        "type": "object",
        "additionalProperties": False,
        "properties": {
            "path": {
                "type": "string",
                "description": "Relative path inside the workspace.",
            },
            "page": {
                "type": "integer",
                "description": "1-based result page.",
                "minimum": 1,
            },
            "page_size": {
                "type": "integer",
                "description": "Number of directory entries per page.",
                "minimum": 1,
                "maximum": 500,
            },
        },
    }

    def __init__(self, workspace: Path):
        self.workspace = workspace

    def execute(self, arguments: dict[str, Any]):
        target = _resolve_workspace_path(
            self.workspace, str(arguments.get("path") or ".")
        )
        if not target.exists():
            return self.failure("not_found", f"{target} does not exist.")
        rows = []
        for child in sorted(target.iterdir(), key=lambda item: item.name):
            suffix = "/" if child.is_dir() else ""
            rows.append(f"{child.relative_to(self.workspace)}{suffix}")
        page = int(arguments.get("page") or 1)
        page_size = int(arguments.get("page_size") or 100)
        try:
            entries, pagination = paginate_items(rows, page=page, page_size=page_size)
        except ValueError as exc:
            return self.failure("page_out_of_range", str(exc))
        relative_path = (
            "."
            if target == self.workspace
            else str(target.relative_to(self.workspace))
        )
        return self.success(
            data={
                "path": relative_path,
                "entries": entries,
            },
            meta={"pagination": pagination},
        )


class ReadFileTool(Tool):
    name = "read_file"
    description = "Read a UTF-8 text file inside the workspace with pagination."
    parameters = {
        "type": "object",
        "additionalProperties": False,
        "properties": {
            "path": {
                "type": "string",
                "description": "Relative path inside the workspace.",
            },
            "page": {
                "type": "integer",
                "description": "1-based result page.",
                "minimum": 1,
            },
            "page_size": {
                "type": "integer",
                "description": "Number of UTF-8 characters per page.",
                "minimum": 256,
                "maximum": 12000,
            },
        },
        "required": ["path"],
    }

    def __init__(self, workspace: Path):
        self.workspace = workspace

    def execute(self, arguments: dict[str, Any]):
        target = _resolve_workspace_path(self.workspace, str(arguments["path"]))
        content = target.read_text(encoding="utf-8")
        page = int(arguments.get("page") or 1)
        page_size = int(arguments.get("page_size") or 2000)
        try:
            page_content, pagination = paginate_text(
                content,
                page=page,
                page_size=page_size,
            )
        except ValueError as exc:
            return self.failure("page_out_of_range", str(exc))
        return self.success(
            data={
                "path": str(target.relative_to(self.workspace)),
                "encoding": "utf-8",
                "content": page_content,
            },
            meta={"pagination": pagination},
        )


class WriteFileTool(Tool):
    name = "write_file"
    description = "Write a UTF-8 text file inside the workspace."
    parameters = {
        "type": "object",
        "additionalProperties": False,
        "properties": {
            "path": {
                "type": "string",
                "description": "Relative path inside the workspace.",
            },
            "content": {"type": "string", "description": "Text content to write."},
        },
        "required": ["path", "content"],
    }

    def __init__(self, workspace: Path):
        self.workspace = workspace

    def execute(self, arguments: dict[str, Any]):
        target = _resolve_workspace_path(self.workspace, str(arguments["path"]))
        content = str(arguments["content"])
        target.parent.mkdir(parents=True, exist_ok=True)
        target.write_text(content, encoding="utf-8")
        return self.success(
            data={
                "path": str(target.relative_to(self.workspace)),
                "bytes_written": len(content.encode("utf-8")),
                "encoding": "utf-8",
            }
        )


def _resolve_workspace_path(workspace: Path, raw_path: str) -> Path:
    candidate = (workspace / raw_path).resolve()
    workspace_root = workspace.resolve()
    if workspace_root not in candidate.parents and candidate != workspace_root:
        raise ValueError("path escapes the workspace")
    return candidate
