"""
Módulo de Exploración Artificial S3
===================================
AWS S3 es un almacén de objetos planos (Flat Namespace). Funcionalmente, 
no existen las carpetas, solo "claves" largas. 
Este módulo abstrae Boto3 para simular un verdadero "File Explorer"
capaz de extraer jerarquías lógicas limpias de directorios.
"""
import logging
from urllib.parse import urlparse

logger = logging.getLogger(__name__)

class AgS3DirectoryLister:
    """
    Simulador de jerarquías para AWS S3 interactuando con paginadores
    para extraer CommonPrefixes en lugar de objetos crudos iterativamente.
    """
    
    def __init__(self, s3_client=None):
        """
        :param s3_client: Instancia pre-existente Boto3 opcional (inyección).
        """
        if s3_client is None:
            import boto3
            self.s3_client = boto3.client('s3')
        else:
            self.s3_client = s3_client

    def _parse_s3_path(self, s3_path: str):
        if not s3_path.startswith("s3://"):
            raise ValueError("La ruta debe tener el formato s3://bucket/prefijo/")
        
        url = urlparse(s3_path)
        bucket = url.netloc
        prefix = url.path.lstrip('/')
        
        # S3 exige que los prefijos terminen en '/' para listar como carpeta
        if prefix and not prefix.endswith('/'):
            prefix += '/'
            
        return bucket, prefix

    def list_folders(self, s3_path: str) -> list[str]:
        """
        Explora una ruta S3 y devuelve exclusivamente el nombre de las "Sub-Carpetas".
        Ignora totalmente los archivos/objetos.
        
        :param s3_path: URI estilo "s3://bucket/ruta/"
        :return: Lista de subcarpetas relativas y absolutas encontradas.
        """
        bucket, prefix = self._parse_s3_path(s3_path)
        logger.info(f"Escaneando sub-directorios (CommonPrefixes) en {bucket} -> /str(prefix)")
        
        paginator = self.s3_client.get_paginator('list_objects_v2')
        # El delimitador `/` obliga a AWS a colapsar objetos y devolver "Carpetas lógicas"
        pages = paginator.paginate(Bucket=bucket, Prefix=prefix, Delimiter='/')
        
        carpetas_encontradas = []
        for page in pages:
            # Los subdirectorios vienen catalogados bajo la clave "CommonPrefixes"
            if 'CommonPrefixes' in page:
                for cp in page['CommonPrefixes']:
                    folder_path = cp.get('Prefix')
                    if folder_path:
                        carpetas_encontradas.append("s3://" + bucket + "/" + folder_path)
                        
        return carpetas_encontradas

    def count_files(self, s3_path: str, suffix: str = None) -> int:
        """
        Cuenta la cantidad de de archivos (Objetos) dentro de un directorio S3 de manera exacta
        y recursiva, utilizando paginación de AWS nativa para eficiencia de red.
        
        :param s3_path: URI estilo 's3://bucket/ruta/'
        :param suffix: (Opcional) Filtrar el conteo por extensión, ej: '.parquet'
        :return: Cantidad entera de archivos encontrados bajo ese prefijo.
        """
        bucket, prefix = self._parse_s3_path(s3_path)
        logger.info(f"Contando objetos masivamente en {bucket} -> /str(prefix)")
        
        paginator = self.s3_client.get_paginator('list_objects_v2')
        # Sin delimitador: AWS devolverá objetos de forma recursiva infinita hacia abajo
        pages = paginator.paginate(Bucket=bucket, Prefix=prefix)
        
        total_count = 0
        for page in pages:
            if 'Contents' in page:
                for obj in page['Contents']:
                    # AWS S3 crea "Directory Markers" (Archivos de 0 bytes que terminan en '/')
                    if obj['Key'].endswith('/'):
                        continue
                        
                    if suffix:
                        if obj['Key'].endswith(suffix):
                            total_count += 1
                    else:
                        total_count += 1
                    
        return total_count

    def list_files(self, s3_path: str, suffix: str = None) -> list[str]:
        """
        Explora una ruta S3 recursivamente y devuelve una lista con las URIs de los archivos (Objetos).
        Ideal para recolectar 500 archivos y enviarlos al AgStreamConcatenator.
        
        :param s3_path: URI estilo 's3://bucket/ruta/'
        :param suffix: (Opcional) Filtrar el conteo por extensión, ej: '.csv'
        :return: Lista de Strings conteniendo URIs puras (s3://bucket/key)
        """
        bucket, prefix = self._parse_s3_path(s3_path)
        logger.info(f"Listando objetos masivamente en {bucket} -> /str(prefix)")
        
        paginator = self.s3_client.get_paginator('list_objects_v2')
        pages = paginator.paginate(Bucket=bucket, Prefix=prefix)
        
        found_files = []
        for page in pages:
            if 'Contents' in page:
                for obj in page['Contents']:
                    key = obj['Key']
                    
                    # Ignorar los "Directory Markers" silenciosos
                    if key.endswith('/'):
                        continue
                        
                    if suffix is None or key.endswith(suffix):
                        found_files.append(f"s3://{bucket}/{key}")
                        
        return found_files

    def print_tree(self, s3_path: str):
        """
        Imprime visualmente (Stdout) los resultados a manera de explorador lógico.
        """
        folders = self.list_folders(s3_path)
        print(f"📦 {s3_path}")
        if not folders:
            print("   └── (Vacío o Sin sub-directorios lógicos)")
        for f in folders:
            print(f"   └── 📁 {f.split('/')[-2]}/")
