"""Wrapper de caché para Folder en modo desarrollo."""

from typing import TYPE_CHECKING, List, Optional, Union
from pathlib import Path
from datetime import datetime
import os

if TYPE_CHECKING:
    from ..base.folder import Folder
    from ..base.file import File
    from .cached_origin import CachedOrigin

from .cached_file import CachedFile
from tai_alphi import Alphi

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


class CachedFolder:
    """
    Wrapper que agrega caché local a cualquier Folder.
    
    Todas las operaciones se delegan al folder remoto,
    pero los archivos se devuelven como CachedFile.
    """
    
    def __init__(self, remote_folder: 'Folder', cache_folder: 'Folder', origin: 'CachedOrigin'):
        """
        Inicializa la carpeta con caché.
        
        Args:
            remote_folder: Carpeta remota original
            cache_folder: Carpeta local que actúa como caché
            origin: CachedOrigin padre
        """
        self._remote = remote_folder
        self._cache = cache_folder
        self._origin = origin
        
        logger.debug(f"CachedFolder inicializado: {remote_folder.path}")
    
    def exists(self) -> bool:
        """
        Verifica si la carpeta existe en el origen remoto.
        
        Returns:
            True si existe, False si no
        """
        return self._remote.exists()
    
    def create(self, parents: bool = True) -> None:
        """
        Crea la carpeta en el origen remoto y en caché.
        
        Args:
            parents: Si True, crea carpetas padres necesarias
        """
        logger.info(f"Creando carpeta (remoto + caché): {self._remote.path}")
        
        # Crear en remoto
        self._remote.create(parents=parents)
        
        # Crear en caché
        self._cache.create(parents=parents)
    
    def delete(self, recursive: bool = False) -> None:
        """
        Elimina la carpeta del origen remoto y del caché.
        
        Args:
            recursive: Si True, elimina recursivamente todo el contenido
        """
        logger.warning(f"Eliminando carpeta (remoto + caché): {self._remote.path} (recursive={recursive})")
        
        # Eliminar del remoto
        if self._remote.exists():
            self._remote.delete(recursive=recursive)
        
        # Eliminar del caché
        if self._cache.exists():
            self._cache.delete(recursive=recursive)
    
    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['CachedFile']:
        """
        Lista archivos en la carpeta remota.
        Devuelve CachedFile para cada archivo.
        
        Args:
            pattern: Patrón regex para filtrar nombres
            recursive: Si True, busca recursivamente en subdirectorios
            modified_after: Filtrar archivos modificados después de esta fecha
            modified_before: Filtrar archivos modificados antes de esta fecha
            created_after: Filtrar archivos creados después de esta fecha
            created_before: Filtrar archivos creados antes de esta fecha
            
        Returns:
            Lista de objetos CachedFile
        """
        logger.debug(f"Listando archivos en: {self._remote.path} (recursive={recursive})")
        
        # Listar archivos del folder remoto
        remote_files = self._remote.list_files(
            pattern=pattern,
            recursive=recursive,
            modified_after=modified_after,
            modified_before=modified_before,
            created_after=created_after,
            created_before=created_before
        )
        
        # Convertir a CachedFile
        cached_files = []
        for remote_file in remote_files:
            # Obtener el archivo de caché correspondiente
            cache_file = self._cache.get_file(remote_file.filename)
            
            # Crear CachedFile
            cached_file = CachedFile(remote_file, cache_file, self)
            cached_files.append(cached_file)
        
        logger.debug(f"Encontrados {len(cached_files)} archivos")
        return cached_files
    
    def list_folders(self, pattern: Optional[str] = None) -> List['CachedFolder']:
        """
        Lista subcarpetas.
        Devuelve CachedFolder para cada carpeta.
        
        Args:
            pattern: Patrón regex para filtrar nombres
            
        Returns:
            Lista de objetos CachedFolder
        """
        logger.debug(f"Listando subcarpetas en: {self._remote.path}")
        
        # Listar carpetas remotas
        remote_folders = self._remote.list_folders(pattern=pattern)
        
        # Convertir a CachedFolder
        cached_folders = []
        for remote_folder in remote_folders:
            # Obtener la carpeta de caché correspondiente
            # Extraer el nombre relativo de la carpeta
            folder_name = os.path.basename(remote_folder.path)
            cache_folder = self._origin._cache_origin.get_folder(
                os.path.join(self._cache.path, folder_name)
            )
            
            # Crear CachedFolder
            cached_folder = CachedFolder(remote_folder, cache_folder, self._origin)
            cached_folders.append(cached_folder)
        
        logger.debug(f"Encontradas {len(cached_folders)} subcarpetas")
        return cached_folders
    
    def get_file(self, filename: str) -> CachedFile:
        """
        Obtiene una referencia a un archivo como CachedFile.
        
        Args:
            filename: Nombre del archivo (puede ser ruta relativa)
            
        Returns:
            Objeto CachedFile
        """
        logger.debug(f"Obteniendo archivo: {filename}")
        
        # Obtener archivos remoto y de caché
        remote_file = self._remote.get_file(filename)
        cache_file = self._cache.get_file(filename)
        
        return CachedFile(remote_file, cache_file, self)
    
    def upload_file(
        self,
        source: Union[str, Path, bytes],
        destination: str,
        overwrite: bool = True
    ) -> CachedFile:
        """
        Sube un archivo al folder remoto y actualiza el caché.
        
        Args:
            source: Ruta del archivo local, Path o bytes a subir
            destination: Nombre del archivo destino
            overwrite: Si True, sobrescribe si existe
            
        Returns:
            Objeto CachedFile del archivo subido
        """
        logger.info(f"Subiendo archivo a: {destination}")
        
        # Subir al remoto
        remote_file = self._remote.upload_file(source, destination, overwrite=overwrite)
        
        # Obtener el archivo de caché
        cache_file = self._cache.get_file(destination)
        
        # Actualizar caché
        if isinstance(source, bytes):
            cache_file.write(source)
        else:
            # Leer desde el archivo local y escribir al caché
            source_path = Path(source)
            with open(source_path, 'rb') as f:
                data = f.read()
            cache_file.write(data)
        
        logger.debug(f"Archivo subido y cacheado: {destination}")
        
        return CachedFile(remote_file, cache_file, self)
    
    def delete_file(self, filename: str) -> None:
        """
        Elimina un archivo del folder remoto y del caché.
        
        Args:
            filename: Nombre del archivo a eliminar
        """
        logger.warning(f"Eliminando archivo (remoto + caché): {filename}")
        
        # Eliminar del remoto
        self._remote.delete_file(filename)
        
        # Eliminar del caché
        cache_file = self._cache.get_file(filename)
        if cache_file.exists():
            cache_file.delete()
    
    @property
    def path(self) -> str:
        """Ruta de la carpeta."""
        return self._remote.path
    
    @property
    def name(self) -> str:
        """Nombre de la carpeta."""
        return self._remote.name
    
    @property
    def origin(self) -> 'CachedOrigin':
        """Origen al que pertenece esta carpeta."""
        return self._origin
    
    def __repr__(self) -> str:
        """Representación de la carpeta."""
        return f"CachedFolder({self._remote.path})"
