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

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

if TYPE_CHECKING:
    from ..base.origin import Origin
    from ..base.folder import Folder

from .cached_folder import CachedFolder
from .cached_file import CachedFile
from ..implementations.local.origin import LocalOrigin
from tai_alphi import Alphi

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


class CachedOrigin:
    """
    Wrapper que agrega caché local a cualquier Origin.
    
    Usa un LocalOrigin internamente como almacenamiento de caché.
    Todas las operaciones se delegan al origin remoto, pero los
    archivos leídos se cachean localmente para acelerar accesos futuros.
    """
    
    def __init__(self, remote_origin: 'Origin', cache_path: str = '.cached_storage'):
        """
        Inicializa el origin con caché.
        
        Args:
            remote_origin: Origin remoto original (Azure, SharePoint, SFTP, etc.)
            cache_path: Ruta donde se almacenará el caché local
        """
        self._remote_origin = remote_origin
        self._cache_path = Path(cache_path)
        
        # Crear LocalOrigin para manejar el caché
        self._cache_origin = LocalOrigin(root_path=str(self._cache_path))
        
        logger.info(f"CachedOrigin inicializado con caché en: {cache_path}")
        logger.debug(f"Origin remoto: {type(remote_origin).__name__}")
    
    def connect(self) -> None:
        """Conecta al origin remoto."""
        logger.debug("Conectando a origin remoto...")
        self._remote_origin.connect()
        
        # Asegurar que el directorio de caché existe
        if not self._cache_path.exists():
            self._cache_path.mkdir(parents=True, exist_ok=True)
            logger.debug(f"Directorio de caché creado: {self._cache_path}")
    
    def disconnect(self) -> None:
        """Desconecta del origin remoto."""
        logger.debug("Desconectando de origin remoto...")
        self._remote_origin.disconnect()
    
    def is_connected(self) -> bool:
        """
        Verifica si está conectado al origin remoto.
        
        Returns:
            True si está conectado, False si no
        """
        return self._remote_origin.is_connected()
    
    def get_folder(self, path: str = "") -> CachedFolder:
        """
        Obtiene una referencia a una carpeta como CachedFolder.
        
        Args:
            path: Ruta de la carpeta (vacío = raíz)
            
        Returns:
            Objeto CachedFolder
        """
        logger.debug(f"Obteniendo carpeta con caché: {path}")
        
        # Obtener folder remoto
        remote_folder = self._remote_origin.get_folder(path)
        
        # Obtener folder de caché correspondiente
        cache_folder = self._cache_origin.get_folder(path)
        
        return CachedFolder(remote_folder, cache_folder, self)
    
    def create_folder(self, path: str, parents: bool = True) -> CachedFolder:
        """
        Crea una carpeta en el origin remoto y en caché.
        
        Args:
            path: Ruta de la carpeta a crear
            parents: Si True, crea carpetas padres necesarias
            
        Returns:
            Objeto CachedFolder de la carpeta creada
        """
        logger.info(f"Creando carpeta: {path} (parents={parents})")
        
        # Crear en remoto
        remote_folder = self._remote_origin.create_folder(path, parents=parents)
        
        # Crear en caché
        cache_folder = self._cache_origin.create_folder(path, parents=parents)
        
        return CachedFolder(remote_folder, cache_folder, self)
    
    def delete_folder(self, path: str, recursive: bool = False) -> None:
        """
        Elimina una carpeta del origin remoto y del caché.
        
        Args:
            path: Ruta de la carpeta a eliminar
            recursive: Si True, elimina recursivamente
        """
        logger.warning(f"Eliminando carpeta: {path} (recursive={recursive})")
        
        # Eliminar del remoto
        self._remote_origin.delete_folder(path, recursive=recursive)
        
        # Eliminar del caché
        if self._cache_origin.folder_exists(path):
            self._cache_origin.delete_folder(path, recursive=recursive)
    
    def folder_exists(self, path: str) -> bool:
        """
        Verifica si una carpeta existe en el origin remoto.
        
        Args:
            path: Ruta de la carpeta
            
        Returns:
            True si existe, False si no
        """
        return self._remote_origin.folder_exists(path)
    
    def list_folders(self, path: str = "", pattern: Optional[str] = None) -> List[CachedFolder]:
        """
        Lista carpetas en una ruta del origin remoto.
        
        Args:
            path: Ruta donde buscar carpetas (vacío = raíz)
            pattern: Patrón regex opcional para filtrar
            
        Returns:
            Lista de objetos CachedFolder
        """
        logger.debug(f"Listando carpetas en: {path}")
        
        # Listar carpetas remotas
        remote_folders = self._remote_origin.list_folders(path, pattern=pattern)
        
        # Convertir a CachedFolder
        cached_folders = []
        for remote_folder in remote_folders:
            # Obtener carpeta de caché correspondiente
            cache_folder = self._cache_origin.get_folder(remote_folder.path)
            
            # Crear CachedFolder
            cached_folder = CachedFolder(remote_folder, cache_folder, self)
            cached_folders.append(cached_folder)
        
        logger.debug(f"Encontradas {len(cached_folders)} carpetas")
        return cached_folders
    
    def get_file(self, path: str) -> CachedFile:
        """
        Obtiene una referencia a un archivo como CachedFile.
        
        Args:
            path: Ruta completa del archivo
            
        Returns:
            Objeto CachedFile
        """
        logger.debug(f"Obteniendo archivo con caché: {path}")
        
        # Separar directorio y nombre de archivo
        dir_path = os.path.dirname(path)
        filename = os.path.basename(path)
        
        # Obtener folder que contiene el archivo
        folder = self.get_folder(dir_path)
        
        # Obtener el archivo desde el folder
        return folder.get_file(filename)
    
    def clear_cache(self, path: Optional[str] = None) -> None:
        """
        Limpia el caché completamente o para una ruta específica.
        
        Args:
            path: Si se especifica, limpia solo ese path. Si None, limpia todo.
        """
        if path is None:
            logger.warning(f"Limpiando todo el caché: {self._cache_path}")
            if self._cache_path.exists():
                import shutil
                shutil.rmtree(self._cache_path)
                self._cache_path.mkdir(parents=True, exist_ok=True)
        else:
            logger.warning(f"Limpiando caché de: {path}")
            # Intentar como carpeta primero
            if self._cache_origin.folder_exists(path):
                self._cache_origin.delete_folder(path, recursive=True)
                return
            
            # Intentar como archivo
            dir_path = os.path.dirname(path)
            filename = os.path.basename(path)
            
            try:
                cache_folder = self._cache_origin.get_folder(dir_path)
                cache_file = cache_folder.get_file(filename)
                if cache_file.exists():
                    cache_file.delete()
                    logger.debug(f"Archivo de caché eliminado: {path}")
            except Exception as e:
                logger.debug(f"No se pudo eliminar caché de {path}: {e}")
    
    @property
    def remote_origin(self) -> 'Origin':
        """Acceso al origin remoto original."""
        return self._remote_origin
    
    @property
    def cache_path(self) -> Path:
        """Ruta del directorio de caché."""
        return self._cache_path
    
    def __enter__(self):
        """Soporte para context manager."""
        self.connect()
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        """Soporte para context manager."""
        self.disconnect()
        return False
    
    def __repr__(self) -> str:
        """Representación del origin."""
        return f"CachedOrigin({type(self._remote_origin).__name__}, cache={self._cache_path})"
