"""
Storage Backend Base Class

Abstract interface for storage implementations
"""

from abc import ABC, abstractmethod
from typing import Optional, BinaryIO
from pathlib import Path


class StorageBackend(ABC):
    """
    Abstract base class for storage backends

    Implementations:
    - LocalStorage: Filesystem storage (development)
    - S3Storage: S3-compatible object storage (production)
    """

    @abstractmethod
    def save_file(self, file_hash: str, content: bytes, filename: Optional[str] = None) -> str:
        """
        Save file to storage

        Args:
            file_hash: SHA256 hash of file (used as key)
            content: File content as bytes
            filename: Original filename (optional, for metadata)

        Returns:
            Storage path/URL where file was saved

        Raises:
            StorageError: If save fails
        """
        pass

    @abstractmethod
    def get_file(self, file_hash: str) -> bytes:
        """
        Retrieve file from storage

        Args:
            file_hash: SHA256 hash of file

        Returns:
            File content as bytes

        Raises:
            FileNotFoundError: If file doesn't exist
            StorageError: If retrieval fails
        """
        pass

    @abstractmethod
    def file_exists(self, file_hash: str) -> bool:
        """
        Check if file exists in storage

        Args:
            file_hash: SHA256 hash of file

        Returns:
            True if file exists, False otherwise
        """
        pass

    @abstractmethod
    def delete_file(self, file_hash: str) -> bool:
        """
        Delete file from storage

        Args:
            file_hash: SHA256 hash of file

        Returns:
            True if deleted, False if file didn't exist

        Raises:
            StorageError: If deletion fails
        """
        pass

    @abstractmethod
    def get_file_url(self, file_hash: str) -> str:
        """
        Get URL for accessing file

        Args:
            file_hash: SHA256 hash of file

        Returns:
            URL string (file:// for local, https:// for S3)
        """
        pass

    def get_file_path(self, file_hash: str) -> str:
        """
        Get storage path for file hash

        Uses content-addressed storage pattern: first 2+2 chars for sharding
        Example: abc123...def -> ab/c1/abc123...def.sub

        Args:
            file_hash: SHA256 hash (64 hex characters)

        Returns:
            Relative storage path
        """
        if len(file_hash) < 4:
            raise ValueError(f"Invalid file hash: {file_hash}")

        # Shard by first 2+2 characters (prevents too many files in one directory)
        shard1 = file_hash[:2]
        shard2 = file_hash[2:4]
        filename = f"{file_hash}.sub"

        return f"{shard1}/{shard2}/{filename}"


class StorageError(Exception):
    """Base exception for storage errors"""
    pass
