"""Read file tool."""


TOOL_VERSION = "2026-05-22"

from __future__ import annotations

import locale
from pathlib import Path
from typing import Callable

from harzoo.agent.kernel.tool import Tool, ToolResult


def resolve_tool_path(path: str) -> Path:
    p = Path(path).expanduser()
    if p.is_absolute():
        return p.resolve()
    return (Path.cwd() / p).resolve()


def decode_bytes_prefer_default(data: bytes) -> tuple[str, str]:
    default_encoding = (locale.getpreferredencoding(False) or "").strip().lower()
    if default_encoding in ("utf8", "cp65001"):
        default_encoding = "utf-8"
    encodings = ["utf-8"] if not default_encoding or default_encoding == "utf-8" else [default_encoding, "utf-8"]
    for encoding in encodings:
        try:
            return data.decode(encoding), encoding
        except (UnicodeDecodeError, LookupError):
            continue
    return data.decode("utf-8", errors="replace"), "utf-8 (replace)"


def read_file_text(path: Path) -> tuple[str, str]:
    return decode_bytes_prefer_default(path.read_bytes())


def safe_file_op(fn: Callable) -> Callable:
    def wrapper(self, file_path: str, *args, **kwargs):
        try:
            return fn(self, file_path, *args, **kwargs)
        except FileNotFoundError:
            return ToolResult.failure(f"File not found: {file_path}", code="FILE_NOT_FOUND")
        except PermissionError as e:
            return ToolResult.failure(str(e), code="PERMISSION_DENIED")
        except Exception as e:
            return ToolResult.failure(str(e), code="TOOL_EXCEPTION")

    return wrapper


class ReadTool(Tool):
    name = "Read"
    description = "Read file contents. Paths are relative to workspace unless absolute."
    parameters = {
        "properties": {
            "file_path": {"type": "string", "description": "Path to the file"},
            "offset": {"type": "integer", "description": "1-based line number to start from"},
            "limit": {"type": "integer", "description": "Maximum lines to read"},
        },
        "required": ["file_path"],
    }

    @safe_file_op
    def execute(self, file_path: str, offset: int | None = None, limit: int | None = None, **kwargs) -> ToolResult:
        p = resolve_tool_path(file_path)
        raw, encoding_used = read_file_text(p)
        lines = raw.splitlines()
        if offset is not None:
            lines = lines[max(0, offset - 1) :]
        if limit is not None:
            lines = lines[:limit]
        return ToolResult.success(
            {
                "text": "\n".join(lines),
                "file_path": str(p),
                "line_count": len(lines),
                "encoding_used": encoding_used,
            }
        )


TOOL = ReadTool
