"""
Module: sandbox.backends.files
Description: Local file storage backend using the filesystem.

Implements:
    - docs/cli/reference.md#huitzo-dev
    - docs/guides/developer-environment.md#development-session-flow

See Also:
    - docs/sdk/integrations.md#file-integration
"""

from __future__ import annotations

from pathlib import Path
from typing import Any

from huitzo_sdk.errors import StorageError


class LocalFileBackend:
    """Local filesystem backend for sandbox development.

    Satisfies the huitzo_sdk FileStorageBackend protocol.
    All files are stored under root_dir with path traversal prevention.
    """

    def __init__(self, root_dir: Path) -> None:
        self._root = root_dir
        self._root.mkdir(parents=True, exist_ok=True)

    def _resolve(self, path: str) -> Path:
        """Resolve a relative path safely within root_dir."""
        resolved = (self._root / path).resolve()
        try:
            resolved.relative_to(self._root.resolve())
        except ValueError:
            raise StorageError(
                operation="resolve",
                key=path,
                message=f"Path traversal denied: '{path}' escapes sandbox root.",
            )
        return resolved

    async def read(self, path: str) -> bytes:
        target = self._resolve(path)
        if not target.exists():
            raise StorageError(
                operation="read",
                key=path,
                message=f"File not found: '{path}'",
            )
        return target.read_bytes()

    async def write(self, path: str, content: bytes) -> None:
        target = self._resolve(path)
        target.parent.mkdir(parents=True, exist_ok=True)
        target.write_bytes(content)

    async def info(self, path: str) -> dict[str, Any]:
        target = self._resolve(path)
        if not target.exists():
            raise StorageError(
                operation="info",
                key=path,
                message=f"File not found: '{path}'",
            )
        stat = target.stat()
        return {
            "name": target.name,
            "size": stat.st_size,
            "modified": stat.st_mtime,
        }

    async def list(self, prefix: str) -> list[dict[str, Any]]:
        base = self._resolve(prefix) if prefix else self._root
        if not base.exists():
            return []
        results = []
        for item in sorted(base.iterdir()):
            if item.is_file():
                rel = str(item.relative_to(self._root))
                results.append({"name": item.name, "path": rel, "size": item.stat().st_size})
        return results

    async def exists(self, path: str) -> bool:
        return self._resolve(path).exists()

    async def get_url(self, path: str, *, expires: int) -> str:
        target = self._resolve(path)
        return target.as_uri()
