import boto3
import os
from botocore.exceptions import ClientError
from typing import List, Dict, Any
from fastapi import UploadFile
from .base_storage import StorageInterface

class S3Storage(StorageInterface):
    def __init__(self, bucket_name: str, region: str, access_key: str, secret_key: str):
        self.bucket_name = bucket_name
        self.s3_client = boto3.client(
            's3',
            region_name=region,
            aws_access_key_id=access_key,
            aws_secret_access_key=secret_key
        )
    
    async def save_files(self, folder_path: str, files: List[UploadFile]) -> Dict[str, Any]:
        uploaded_files = []
        
        for file in files:
            file_key = f"{folder_path}/{file.filename}"
            
            try:
                # Leer el contenido del archivo
                file.file.seek(0)
                content = await file.read()
                
                # Subir archivo a S3
                self.s3_client.put_object(
                    Bucket=self.bucket_name,
                    Key=file_key,
                    Body=content,
                    ContentType=file.content_type
                )
                
                # Generar URL pública
                file_url = f"https://{self.bucket_name}.s3.us-east-2.amazonaws.com/{file_key}"
                uploaded_files.append({
                    'filename': file.filename,
                    's3_key': file_key,
                    'url': file_url,
                    'size': len(content)
                })
                
            except ClientError as e:
                return {
                    "success": False,
                    "message": f"Error al subir {file.filename}: {str(e)}"
                }
        
        return {
            "success": True,
            "message": "Archivos subidos exitosamente",
            "files": uploaded_files
        }
    
    async def get_file_url(self, file_path: str) -> str:
        return f"https://{self.bucket_name}.s3.us-east-2.amazonaws.com/{file_path}"
    
    async def delete_file(self, file_path: str) -> bool:
        try:
            self.s3_client.delete_object(Bucket=self.bucket_name, Key=file_path)
            return True
        except ClientError:
            return False
    
    async def list_files(self, folder_path: str) -> List[str]:
        try:
            response = self.s3_client.list_objects_v2(
                Bucket=self.bucket_name,
                Prefix=folder_path
            )
            return [obj['Key'] for obj in response.get('Contents', [])]
        except ClientError:
            return []
    
    async def list_files_with_metadata(self, folder_path: str, max_files: int = 5) -> Dict[str, Any]:
        """
        Lista archivos con metadatos sin generar URLs firmadas.
        
        Args:
            folder_path: Ruta de la carpeta en S3
            max_files: Número máximo de archivos a retornar
        
        Returns:
            Dict con información de los archivos (sin URLs firmadas)
        """
        try:
            response = self.s3_client.list_objects_v2(
                Bucket=self.bucket_name,
                Prefix=folder_path
            )
            
            if 'Contents' not in response:
                return {
                    "success": True,
                    "message": "No se encontraron archivos en la carpeta",
                    "files": []
                }
            
            files_info = []
            for obj in response['Contents']:
                if obj['Key'] != folder_path.rstrip('/'):
                    files_info.append({
                        'key': obj['Key'],
                        'filename': obj['Key'].split('/')[-1],
                        'size': obj['Size'],
                        'last_modified': obj['LastModified'],
                        'etag': obj['ETag']
                    })
            
            files_info.sort(key=lambda x: x['last_modified'], reverse=True)
            latest_files = files_info[:max_files]
            
            files_with_metadata = []
            for file_info in latest_files:
                files_with_metadata.append({
                    'filename': file_info['filename'],
                    's3_key': file_info['key'],
                    'size': file_info['size'],
                    'last_modified': file_info['last_modified'].isoformat()
                })
            
            return {
                "success": True,
                "message": f"Archivos listados: {len(files_with_metadata)} archivos",
                "folder_path": folder_path,
                "files": files_with_metadata,
                "total_files_in_folder": len(files_info),
                "files_returned": len(files_with_metadata)
            }
            
        except ClientError as e:
            return {
                "success": False,
                "message": f"Error al listar archivos de S3: {str(e)}",
                "files": []
            }
        except Exception as e:
            return {
                "success": False,
                "message": f"Error inesperado: {str(e)}",
                "files": []
            }
    
    async def get_signed_url(self, s3_key: str, expiration: int = 300) -> Dict[str, Any]:
        """
        Genera una URL firmada para un archivo específico.
        
        Args:
            s3_key: Clave del archivo en S3
            expiration: Tiempo de expiración en segundos
        
        Returns:
            Dict con la URL firmada y metadatos
        """
        try:
            # Verificar que el archivo existe
            try:
                self.s3_client.head_object(Bucket=self.bucket_name, Key=s3_key)
            except ClientError as e:
                if e.response['Error']['Code'] == '404':
                    return {
                        "success": False,
                        "message": "Archivo no encontrado en S3",
                        "data": {}
                    }
                else:
                    raise e
            
            # Generar URL firmada
            signed_url = self.s3_client.generate_presigned_url(
                'get_object',
                Params={
                    'Bucket': self.bucket_name,
                    'Key': s3_key
                },
                ExpiresIn=expiration
            )
            
            # Calcular tiempo de expiración
            from datetime import datetime, timedelta
            expires_at = datetime.now() + timedelta(seconds=expiration)
            
            return {
                "success": True,
                "message": "URL firmada generada exitosamente",
                "signed_url": signed_url,
                "expires_at": expires_at.isoformat(),
                "expires_in": expiration
            }
            
        except ClientError as e:
            return {
                "success": False,
                "message": f"Error al generar URL firmada: {str(e)}",
                "data": {}
            }
        except Exception as e:
            return {
                "success": False,
                "message": f"Error inesperado: {str(e)}",
                "data": {}
            }
