"""File Station metadata tools: get_file_info, get_dir_size."""

from __future__ import annotations

import contextlib
from typing import TYPE_CHECKING, Any

from synology_mcp.core.errors import SynologyError
from synology_mcp.core.formatting import (
    format_error,
    format_key_value,
    format_size,
    format_table,
    format_timestamp,
)
from synology_mcp.modules.filestation.helpers import (
    escape_multi_path,
    normalize_path,
)

if TYPE_CHECKING:
    from synology_mcp.core.client import DsmClient


async def get_file_info(
    client: DsmClient,
    *,
    paths: list[str],
    additional: list[str] | None = None,
) -> str:
    """Get detailed metadata for specific files or folders."""
    if additional is None:
        additional = ["real_path", "size", "owner", "time", "perm"]

    normalized = [normalize_path(p) for p in paths]
    path_param = escape_multi_path(normalized)

    try:
        data = await client.request(
            "SYNO.FileStation.List",
            "getinfo",
            params={
                "path": path_param,
                "additional": '["' + '","'.join(additional) + '"]',
            },
        )
    except SynologyError as e:
        return format_error("Get file info", str(e), e.suggestion)

    files = data.get("files", [])

    if len(files) == 1:
        return _format_single_info(files[0])

    # Multiple files: table format
    if not files:
        return format_error(
            "Get file info",
            "No file information returned.",
            "Check that the paths exist.",
        )

    headers = ["Name", "Path", "Type", "Size", "Modified"]
    rows: list[list[str]] = []
    for f in files:
        add_info = f.get("additional", {})
        name = f.get("name", "")
        path = f.get("path", "")
        ftype = "Directory" if f.get("isdir") else "File"
        size = format_size(add_info.get("size", 0)) if not f.get("isdir") else "—"
        mtime = add_info.get("time", {}).get("mtime", 0)
        modified = format_timestamp(mtime) if mtime else "—"
        rows.append([name, path, ftype, size, modified])

    return format_table(headers=headers, rows=rows, title=f"File Info ({len(files)} items)")


def _format_single_info(file_data: dict[str, Any]) -> str:
    """Format detailed info for a single file."""
    add_info = file_data.get("additional", {})
    name = file_data.get("name", "")
    path = file_data.get("path", "")
    is_dir = file_data.get("isdir", False)

    pairs: list[tuple[str, str]] = [
        ("Name", name),
        ("Path", path),
    ]

    real_path = add_info.get("real_path", "")
    if real_path:
        pairs.append(("Real path", real_path))

    pairs.append(("Type", "Directory" if is_dir else "File"))

    if not is_dir:
        pairs.append(("Size", format_size(add_info.get("size", 0))))

    owner_info = add_info.get("owner", {})
    user = owner_info.get("user", "")
    group = owner_info.get("group", "")
    if user:
        owner_str = f"{user} ({group})" if group else user
        pairs.append(("Owner", owner_str))

    time_info = add_info.get("time", {})
    if time_info.get("mtime"):
        pairs.append(("Modified", format_timestamp(time_info["mtime"])))
    if time_info.get("crtime"):
        pairs.append(("Created", format_timestamp(time_info["crtime"])))
    if time_info.get("atime"):
        pairs.append(("Accessed", format_timestamp(time_info["atime"])))

    perm = add_info.get("perm", {})
    if perm.get("posix"):
        pairs.append(("Permissions", str(perm["posix"])))

    return format_key_value(pairs, title=f"File Info: {path}")


async def get_dir_size(
    client: DsmClient,
    *,
    path: str,
    timeout: float = 120.0,
) -> str:
    """Calculate the total size of a directory."""
    normalized = normalize_path(path)

    try:
        start_data = await client.request(
            "SYNO.FileStation.DirSize",
            "start",
            params={"path": normalized},
        )
    except SynologyError as e:
        return format_error("Get directory size", str(e), e.suggestion)

    taskid = start_data.get("taskid", "")

    # Poll for completion
    import asyncio

    elapsed = 0.0
    interval = 0.5

    while elapsed < timeout:
        try:
            status = await client.request(
                "SYNO.FileStation.DirSize",
                "status",
                params={"taskid": taskid},
            )
        except SynologyError as e:
            return format_error("Get directory size", str(e), e.suggestion)

        if status.get("finished", False):
            total_size = status.get("total_size", 0)
            num_file = status.get("num_file", 0)
            num_dir = status.get("num_dir", 0)

            # Stop task
            with contextlib.suppress(SynologyError):
                await client.request(
                    "SYNO.FileStation.DirSize",
                    "stop",
                    params={"taskid": taskid},
                )

            return format_key_value(
                [
                    ("Total size", format_size(total_size)),
                    ("Files", str(num_file)),
                    ("Directories", str(num_dir)),
                ],
                title=f"Directory Size: {normalized}",
            )

        await asyncio.sleep(interval)
        elapsed += interval

    # Timeout
    with contextlib.suppress(SynologyError):
        await client.request("SYNO.FileStation.DirSize", "stop", params={"taskid": taskid})

    return format_error(
        "Get directory size",
        f"Timed out after {timeout}s.",
        "The directory may be very large. Try a subdirectory.",
    )
