"""
Storage convenience wrapper for the Eddytor SDK.

Provides a fluent API so callers don't have to repeat config_id on every call:

    store = client.storage("cfg_xxx")
    objects = store.list_objects(path="data/")
    data, filename = store.download("reports/q4.csv")
    store.create_folder("data/new/")
    store.delete()
"""

from __future__ import annotations

from typing import TYPE_CHECKING, Union

from .exceptions import EddytorError

if TYPE_CHECKING:
    from .client import EddytorClient
    from .models import ListObjectsResult, MoveObjectsResult, StorageConfig


class Storage:
    """
    Lightweight handle for a storage configuration.

    All methods delegate to the parent :class:`EddytorClient`'s
    :class:`RestClient`, filling in the ``config_id`` automatically.
    """

    def __init__(self, client: EddytorClient, config_id: str) -> None:
        self._client = client
        self._config_id = config_id

    @property
    def config_id(self) -> str:
        return self._config_id

    def __repr__(self) -> str:
        return f"Storage({self._config_id!r})"

    # ------------------------------------------------------------------
    # Info
    # ------------------------------------------------------------------

    def info(self) -> StorageConfig:
        """Get the storage configuration for this config_id.

        Raises:
            EddytorError: If the config_id is not found.
        """
        configs = self._client.rest.get_storage_configs()
        for cfg in configs:
            if cfg.id == self._config_id:
                return cfg
        raise EddytorError(f"Storage config {self._config_id!r} not found")

    # ------------------------------------------------------------------
    # Object operations
    # ------------------------------------------------------------------

    def list_objects(
        self,
        path: str = "",
        extensions: str | None = None,
        limit: int = 100,
        continuation_token: str | None = None,
        delimiter: bool = True,
    ) -> ListObjectsResult:
        """List objects in this storage configuration."""
        return self._client.rest.list_objects(
            self._config_id,
            path=path,
            extensions=extensions,
            limit=limit,
            continuation_token=continuation_token,
            delimiter=delimiter,
        )

    def download(self, path: str, inline: bool = False) -> tuple[bytes, str]:
        """Download an object from this storage configuration.

        Returns:
            Tuple of (bytes, filename).
        """
        return self._client.rest.download_object(self._config_id, path, inline=inline)

    def delete_object(self, path: str) -> None:
        """Delete an object from this storage configuration."""
        self._client.rest.delete_object(self._config_id, path)

    def create_folder(self, path: str) -> str:
        """Create a folder in this storage configuration.

        Returns:
            Full path of the created folder.
        """
        return self._client.rest.create_folder(self._config_id, path)

    def move_to(
        self,
        destination: Union[Storage, str],
        source_path: str,
        destination_path: str,
    ) -> MoveObjectsResult:
        """Move objects from this storage to another.

        Args:
            destination: Target storage — a :class:`Storage` instance or a
                config_id string.
            source_path: Path prefix in this storage.
            destination_path: Path prefix in the destination storage.
        """
        dest_id = destination.config_id if isinstance(destination, Storage) else destination
        return self._client.rest.move_objects(
            self._config_id, source_path, dest_id, destination_path,
        )

    # ------------------------------------------------------------------
    # Config lifecycle
    # ------------------------------------------------------------------

    def delete(self) -> None:
        """Delete this storage configuration."""
        self._client.rest.delete_storage_config(self._config_id)
