from minio import Minio
from minio.error import S3Error
from typing import Optional, Tuple
import io
import os
import logging

from app.config.settings import settings


class MinioClient:
    """MinIO客户端类"""
    
    def __init__(self):
        """初始化MinIO客户端"""
        try:
            self.client = Minio(
                settings.MINIO_ENDPOINT,
                access_key=settings.MINIO_ACCESS_KEY,
                secret_key=settings.MINIO_SECRET_KEY,
                secure=settings.MINIO_SECURE
            )
            self.bucket_name = settings.MINIO_BUCKET_NAME
            self.is_connected = True  # 先设置为True，这样在调用其他方法时不会报错
            
            # 确保存储桶存在
            self._ensure_bucket_exists()
        except Exception as e:
            logging.warning(f"Failed to connect to MinIO: {e}. Running in offline mode.")
            self.client = None
            self.bucket_name = settings.MINIO_BUCKET_NAME
            self.is_connected = False
    
    def _ensure_bucket_exists(self):
        """确保存储桶存在"""
        if not self.is_connected:
            return
        
        try:
            if not self.client.bucket_exists(self.bucket_name):
                self.client.make_bucket(self.bucket_name)
        except S3Error as e:
            logging.warning(f"MinIO bucket error: {e}")
    
    def upload_file(self, file_path: str, object_name: str) -> bool:
        """上传文件"""
        if not self.is_connected:
            logging.warning("MinIO is not connected. Upload skipped.")
            return False
        
        try:
            self.client.fput_object(
                self.bucket_name,
                object_name,
                file_path
            )
            return True
        except S3Error as e:
            logging.warning(f"MinIO upload error: {e}")
            return False
    
    def upload_fileobj(self, file_obj: io.BytesIO, object_name: str, content_type: str = "application/octet-stream") -> bool:
        """上传文件对象"""
        if not self.is_connected:
            logging.warning("MinIO is not connected. Upload skipped.")
            return False
        
        try:
            self.client.put_object(
                self.bucket_name,
                object_name,
                file_obj,
                length=-1,
                part_size=10*1024*1024,
                content_type=content_type
            )
            return True
        except S3Error as e:
            logging.warning(f"MinIO upload error: {e}")
            return False
    
    def download_file(self, object_name: str, file_path: str) -> bool:
        """下载文件"""
        if not self.is_connected:
            logging.warning("MinIO is not connected. Download skipped.")
            return False
        
        try:
            self.client.fget_object(
                self.bucket_name,
                object_name,
                file_path
            )
            return True
        except S3Error as e:
            logging.warning(f"MinIO download error: {e}")
            return False
    
    def get_object(self, object_name: str) -> Optional[bytes]:
        """获取对象内容"""
        if not self.is_connected:
            logging.warning("MinIO is not connected. Get object skipped.")
            return None
        
        try:
            response = self.client.get_object(
                self.bucket_name,
                object_name
            )
            data = response.read()
            response.close()
            response.release_conn()
            return data
        except S3Error as e:
            logging.warning(f"MinIO get object error: {e}")
            return None
    
    def delete_object(self, object_name: str) -> bool:
        """删除对象"""
        if not self.is_connected:
            logging.warning("MinIO is not connected. Delete object skipped.")
            return False
        
        try:
            self.client.remove_object(
                self.bucket_name,
                object_name
            )
            return True
        except S3Error as e:
            logging.warning(f"MinIO delete error: {e}")
            return False
    
    def list_objects(self, prefix: str = "") -> list:
        """列出对象"""
        if not self.is_connected:
            logging.warning("MinIO is not connected. List objects skipped.")
            return []
        
        try:
            objects = []
            for obj in self.client.list_objects(
                self.bucket_name,
                prefix=prefix,
                recursive=True
            ):
                objects.append(obj.object_name)
            return objects
        except S3Error as e:
            logging.warning(f"MinIO list objects error: {e}")
            return []
    
    def get_presigned_url(self, object_name: str, expires: int = 604800) -> Optional[str]:
        """获取预签名URL"""
        if not self.is_connected:
            logging.warning("MinIO is not connected. Get presigned URL skipped.")
            return None
        
        try:
            url = self.client.presigned_get_object(
                self.bucket_name,
                object_name,
                expires=expires
            )
            return url
        except S3Error as e:
            logging.warning(f"MinIO presigned url error: {e}")
            return None


# 创建全局文件存储实例
try:
    file_storage = MinioClient()
except Exception as e:
    # 如果初始化失败，创建一个模拟实例
    class MockFileStorage:
        def __getattr__(self, name):
            def mock_method(*args, **kwargs):
                logging.warning(f"MinIO is not available. Method '{name}' will not execute.")
                return None if name.startswith('get_') or name == 'list_objects' else False
            return mock_method
    
    file_storage = MockFileStorage()
    logging.warning(f"Failed to initialize MinIO client: {e}. Using mock instance.")
