"""
Clase base abstracta para Folder (carpetas/contenedores).
"""
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import List, Optional, Dict, Any, TYPE_CHECKING
from datetime import datetime

from tai_alphi import Alphi

if TYPE_CHECKING:
    from .origin import Origin
    from .file import File

logger = Alphi.get_logger_by_name('tai-storage')


class Folder(ABC):
    """
    Clase base abstracta que representa una carpeta/contenedor en un sistema de almacenamiento.
    
    Una carpeta puede ser un directorio local, un contenedor de Azure Blob Storage,
    un directorio SFTP, etc.
    """
    
    def __init__(self, origin: Origin, path: str):
        """
        Inicializa la carpeta.
        
        Args:
            origin: Instancia del origen al que pertenece
            path: Ruta de la carpeta
        """
        self.origin = origin
        self.path = path
        logger.debug(f"Initializing {self.__class__.__name__} at path: {path}")
    
    @abstractmethod
    def list_files(
        self,
        pattern: Optional[str] = None,
        recursive: bool = False,
        modified_after: Optional[datetime] = None,
        modified_before: Optional[datetime] = None,
        created_after: Optional[datetime] = None,
        created_before: Optional[datetime] = None
    ) -> List[File]:
        """
        Lista archivos en la carpeta como objetos File.
        
        Args:
            pattern: Patrón regex opcional para filtrar por nombre
            recursive: Si True, busca recursivamente en subcarpetas
            modified_after: Solo archivos modificados después de esta fecha
            modified_before: Solo archivos modificados antes de esta fecha
            created_after: Solo archivos creados después de esta fecha
            created_before: Solo archivos creados antes de esta fecha
            
        Returns:
            Lista de objetos File que cumplen los criterios
            
        Examples:
            >>> # Listar todos los archivos
            >>> files = folder.list_files()
            
            >>> # Solo PDFs
            >>> pdfs = folder.list_files(pattern=r'.*\.pdf$')
            
            >>> # Archivos recientes
            >>> from datetime import datetime, timedelta
            >>> since = datetime.now() - timedelta(days=7)
            >>> recent = folder.list_files(modified_after=since)
            
            >>> # Combinar filtros
            >>> files = folder.list_files(
            ...     pattern=r'.*\.csv$',
            ...     modified_after=since,
            ...     recursive=True
            ... )
        """
        pass
    
    @abstractmethod
    def list_folders(self, pattern: Optional[str] = None) -> List['Folder']:
        """
        Lista las subcarpetas como objetos Folder.
        
        Args:
            pattern: Patrón regex opcional para filtrar por nombre
            
        Returns:
            Lista de objetos Folder
            
        Examples:
            >>> # Listar todas las subcarpetas
            >>> subfolders = folder.list_folders()
            >>> for subfolder in subfolders:
            ...     print(subfolder.path)
            
            >>> # Solo carpetas que empiezan con 'backup'
            >>> backups = folder.list_folders(pattern=r'^backup.*')
        """
        pass
    
    @abstractmethod
    def get_file(self, filename: str) -> File:
        """
        Obtiene una referencia a un archivo en la carpeta.
        
        Args:
            filename: Nombre del archivo (puede incluir subcarpetas relativas)
            
        Returns:
            Instancia de File
            
        Note:
            No verifica si el archivo existe, solo crea la referencia
        """
        pass
    
    @abstractmethod
    def upload_file(
        self, 
        source: Any, 
        destination: str, 
        overwrite: bool = False
    ) -> File:
        """
        Sube un archivo a la carpeta.
        
        Args:
            source: Origen del archivo (puede ser bytes, path local, stream, etc.)
            destination: Nombre del archivo destino en la carpeta
            overwrite: Si True, sobrescribe si ya existe
            
        Returns:
            Instancia de File del archivo subido
            
        Raises:
            FileAlreadyExistsError: Si el archivo existe y overwrite=False
        """
        pass
    
    @abstractmethod
    def delete_file(self, filename: str) -> None:
        """
        Elimina un archivo de la carpeta.
        
        Args:
            filename: Nombre del archivo a eliminar
            
        Raises:
            FileNotFoundError: Si el archivo no existe
        """
        pass
    
    @abstractmethod
    def exists(self) -> bool:
        """
        Verifica si la carpeta existe.
        
        Returns:
            True si existe, False en caso contrario
        """
        pass
    
    @abstractmethod
    def create(self, parents: bool = True) -> None:
        """
        Crea la carpeta.
        
        Args:
            parents: Si True, crea carpetas padres si no existen
            
        Raises:
            FolderAlreadyExistsError: Si la carpeta ya existe
        """
        pass
    
    @abstractmethod
    def delete(self, recursive: bool = False) -> None:
        """
        Elimina la carpeta.
        
        Args:
            recursive: Si True, elimina contenido recursivamente
            
        Raises:
            FolderNotFoundError: Si la carpeta no existe
        """
        pass
    
    @abstractmethod
    def get_metadata(self) -> Dict[str, Any]:
        """
        Obtiene metadatos de la carpeta.
        
        Returns:
            Diccionario con metadatos (varía según implementación):
            {
                'path': 'ruta/carpeta',
                'created_time': datetime(...),
                'modified_time': datetime(...),
                'file_count': 10,
                ...
            }
        """
        pass
    
    def __repr__(self) -> str:
        """Representación string de la carpeta."""
        return f"<{self.__class__.__name__} path='{self.path}'>"
