"""
Implementación de Folder para sistema de archivos local.
"""
import os
import re
from pathlib import Path
from typing import List, Optional, Dict, Any, TYPE_CHECKING
from datetime import datetime

from tai_alphi import Alphi
from tai_storage.base import Folder
from tai_storage.exceptions import (
    FolderNotFoundError,
    FolderAlreadyExistsError,
    FileNotFoundError,
    FileAlreadyExistsError
)
from tai_storage.utils import match_pattern

if TYPE_CHECKING:
    from .file import LocalFile
    from .origin import LocalOrigin

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


class LocalFolder(Folder):
    """
    Implementación de Folder para directorios en el sistema de archivos local.
    """
    
    def __init__(self, origin: 'LocalOrigin', path: str):
        """
        Inicializa una carpeta local.
        
        Args:
            origin: LocalOrigin al que pertenece
            path: Ruta de la carpeta
        """
        super().__init__(origin, path)
        self._path = Path(path)
    
    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['LocalFile']:
        """Lista archivos como objetos LocalFile con filtrado opcional."""
        from .file import LocalFile
        
        if not self.exists():
            raise FolderNotFoundError(f"Folder not found: {self.path}")
        
        logger.debug(f"Listing files in: {self.path} (recursive={recursive}, pattern={pattern})")
        
        files = []
        
        if recursive:
            # Búsqueda recursiva
            for root, _, filenames in os.walk(self._path):
                for filename in filenames:
                    full_path = os.path.join(root, filename)
                    # Ruta relativa a la carpeta
                    rel_path = os.path.relpath(full_path, self._path)
                    
                    # Aplicar filtro de patrón si existe
                    if pattern and not match_pattern(rel_path, pattern):
                        continue
                    
                    # Crear objeto File
                    file = LocalFile(self, rel_path, full_path)
                    
                    # Filtros de fecha
                    try:
                        if modified_after and file.modified_time < modified_after:
                            continue
                        if modified_before and file.modified_time > modified_before:
                            continue
                        if created_after and file.created_time < created_after:
                            continue
                        if created_before and file.created_time > created_before:
                            continue
                    except Exception as e:
                        logger.warning(f"Error checking dates for {full_path}: {e}")
                        continue
                    
                    files.append(file)
        else:
            # Solo archivos en el nivel actual
            if not self._path.is_dir():
                return []
            
            for item in self._path.iterdir():
                if item.is_file():
                    # Aplicar filtro de patrón si existe
                    if pattern and not match_pattern(item.name, pattern):
                        continue
                    
                    # Crear objeto File
                    file = LocalFile(self, item.name, str(item))
                    
                    # Filtros de fecha
                    try:
                        if modified_after and file.modified_time < modified_after:
                            continue
                        if modified_before and file.modified_time > modified_before:
                            continue
                        if created_after and file.created_time < created_after:
                            continue
                        if created_before and file.created_time > created_before:
                            continue
                    except Exception as e:
                        logger.warning(f"Error checking dates for {item}: {e}")
                        continue
                    
                    files.append(file)
        
        logger.debug(f"Found {len(files)} files")
        return files
    
    def list_folders(self, pattern: Optional[str] = None) -> List['LocalFolder']:
        """Lista las subcarpetas como objetos LocalFolder."""
        if not self.exists():
            raise FolderNotFoundError(f"Folder not found: {self.path}")
        
        logger.debug(f"Listing folders in: {self.path}")
        
        folders = []
        
        if not self._path.is_dir():
            return []
        
        for item in self._path.iterdir():
            if item.is_dir():
                # Aplicar filtro de patrón si existe
                if pattern and not match_pattern(item.name, pattern):
                    continue
                
                # Crear objeto Folder
                folder_path = str(item)
                folder = LocalFolder(self.origin, folder_path)
                folders.append(folder)
        
        logger.debug(f"Found {len(folders)} folders")
        return folders
    
    def get_file(self, filename: str) -> 'LocalFile':
        """Obtiene una referencia a un archivo en la carpeta."""
        from .file import LocalFile
        
        full_path = os.path.join(self.path, filename)
        logger.debug(f"Getting file reference: {full_path}")
        return LocalFile(self, filename, full_path)
    
    def upload_file(
        self, 
        source: Any, 
        destination: str, 
        overwrite: bool = False
    ) -> 'LocalFile':
        """
        Sube un archivo a la carpeta.
        
        Args:
            source: Puede ser bytes, str (path), Path, o file-like object
            destination: Nombre del archivo destino
            overwrite: Si True, sobrescribe si existe
        """
        dest_file = self.get_file(destination)
        
        if dest_file.exists() and not overwrite:
            raise FileAlreadyExistsError(f"File already exists: {dest_file.full_path}")
        
        logger.info(f"Uploading file to: {dest_file.full_path}")
        
        # Determinar tipo de source y procesar
        if isinstance(source, bytes):
            # Source es bytes directamente
            dest_file.write(source, overwrite=overwrite)
        elif isinstance(source, str):
            # Source es una ruta de archivo
            source_path = Path(source)
            if not source_path.is_file():
                raise FileNotFoundError(f"Source file not found: {source}")
            data = source_path.read_bytes()
            dest_file.write(data, overwrite=overwrite)
        elif isinstance(source, Path):
            # Source es un Path
            if not source.is_file():
                raise FileNotFoundError(f"Source file not found: {source}")
            data = source.read_bytes()
            dest_file.write(data, overwrite=overwrite)
        elif hasattr(source, 'read'):
            # Source es file-like object
            data = source.read()
            if isinstance(data, str):
                dest_file.write_text(data, overwrite=overwrite)
            else:
                dest_file.write(data, overwrite=overwrite)
        else:
            raise ValueError(f"Unsupported source type: {type(source)}")
        
        return dest_file
    
    def delete_file(self, filename: str) -> None:
        """Elimina un archivo de la carpeta."""
        file = self.get_file(filename)
        if not file.exists():
            raise FileNotFoundError(f"File not found: {file.full_path}")
        
        file.delete()
    
    def exists(self) -> bool:
        """Verifica si la carpeta existe."""
        return self._path.is_dir()
    
    def create(self, parents: bool = True) -> None:
        """Crea la carpeta."""
        if self.exists():
            raise FolderAlreadyExistsError(f"Folder already exists: {self.path}")
        
        logger.info(f"Creating folder: {self.path}")
        self._path.mkdir(parents=parents, exist_ok=False)
    
    def delete(self, recursive: bool = False) -> None:
        """Elimina la carpeta."""
        if not self.exists():
            raise FolderNotFoundError(f"Folder not found: {self.path}")
        
        logger.info(f"Deleting folder: {self.path} (recursive={recursive})")
        
        if recursive:
            import shutil
            shutil.rmtree(self._path)
        else:
            # Solo elimina si está vacía
            self._path.rmdir()
    
    def get_metadata(self) -> Dict[str, Any]:
        """Obtiene metadatos de la carpeta."""
        if not self.exists():
            raise FolderNotFoundError(f"Folder not found: {self.path}")
        
        stat = self._path.stat()
        
        # Contar archivos y subcarpetas
        file_count = len([item for item in self._path.iterdir() if item.is_file()])
        folder_count = len([item for item in self._path.iterdir() if item.is_dir()])
        
        return {
            'path': self.path,
            'created_time': datetime.fromtimestamp(stat.st_ctime),
            'modified_time': datetime.fromtimestamp(stat.st_mtime),
            'file_count': file_count,
            'folder_count': folder_count,
            'is_folder': True,
            'permissions': oct(stat.st_mode),
        }
