"""
S3-Compatible Object Storage Backend

For production mode - stores files in S3 or MinIO
"""

from typing import Optional
from loguru import logger

from .base import StorageBackend, StorageError


class S3Storage(StorageBackend):
    """
    S3-compatible object storage implementation

    Supports:
    - AWS S3
    - MinIO
    - Any S3-compatible storage
    """

    def __init__(
        self,
        bucket: str,
        access_key: str,
        secret_key: str,
        endpoint: Optional[str] = None,
        region: str = "us-east-1"
    ):
        """
        Initialize S3 storage

        Args:
            bucket: S3 bucket name
            access_key: AWS access key ID
            secret_key: AWS secret access key
            endpoint: Custom endpoint (for MinIO, etc.)
            region: AWS region
        """
        self.bucket = bucket
        self.access_key = access_key
        self.secret_key = secret_key
        self.endpoint = endpoint
        self.region = region

        # Import boto3 lazily (only in production)
        try:
            import boto3
            from botocore.exceptions import ClientError

            self.boto3 = boto3
            self.ClientError = ClientError

            # Create S3 client
            self.s3_client = boto3.client(
                's3',
                aws_access_key_id=access_key,
                aws_secret_access_key=secret_key,
                endpoint_url=endpoint,
                region_name=region
            )

            # Verify bucket exists
            try:
                self.s3_client.head_bucket(Bucket=bucket)
                logger.info(f"S3Storage initialized: bucket={bucket}, region={region}")
            except self.ClientError:
                logger.error(f"S3 bucket not accessible: {bucket}")
                raise StorageError(f"S3 bucket not accessible: {bucket}")

        except ImportError:
            raise StorageError("boto3 not installed. Install with: pip install boto3")

    def save_file(self, file_hash: str, content: bytes, filename: Optional[str] = None) -> str:
        """Upload file to S3"""
        try:
            # Get storage key
            key = self.get_file_path(file_hash)

            # Upload to S3
            self.s3_client.put_object(
                Bucket=self.bucket,
                Key=key,
                Body=content,
                ContentType='application/octet-stream',
                Metadata={
                    'original_filename': filename or '',
                    'file_hash': file_hash
                }
            )

            logger.debug(f"File uploaded to S3: {key} ({len(content)} bytes)")

            return key

        except self.ClientError as e:
            logger.error(f"Failed to upload file to S3 {file_hash}: {e}")
            raise StorageError(f"Failed to upload file: {e}")

    def get_file(self, file_hash: str) -> bytes:
        """Download file from S3"""
        try:
            key = self.get_file_path(file_hash)

            # Download from S3
            response = self.s3_client.get_object(
                Bucket=self.bucket,
                Key=key
            )

            content = response['Body'].read()

            logger.debug(f"File downloaded from S3: {key} ({len(content)} bytes)")

            return content

        except self.ClientError as e:
            if e.response['Error']['Code'] == 'NoSuchKey':
                raise FileNotFoundError(f"File not found: {file_hash}")
            logger.error(f"Failed to download file from S3 {file_hash}: {e}")
            raise StorageError(f"Failed to download file: {e}")

    def file_exists(self, file_hash: str) -> bool:
        """Check if file exists in S3"""
        try:
            key = self.get_file_path(file_hash)

            self.s3_client.head_object(
                Bucket=self.bucket,
                Key=key
            )

            return True

        except self.ClientError as e:
            if e.response['Error']['Code'] == '404':
                return False
            logger.error(f"Failed to check file existence in S3 {file_hash}: {e}")
            return False

    def delete_file(self, file_hash: str) -> bool:
        """Delete file from S3"""
        try:
            key = self.get_file_path(file_hash)

            # Check if file exists first
            if not self.file_exists(file_hash):
                return False

            # Delete from S3
            self.s3_client.delete_object(
                Bucket=self.bucket,
                Key=key
            )

            logger.debug(f"File deleted from S3: {key}")

            return True

        except self.ClientError as e:
            logger.error(f"Failed to delete file from S3 {file_hash}: {e}")
            raise StorageError(f"Failed to delete file: {e}")

    def get_file_url(self, file_hash: str, expires_in: int = 3600) -> str:
        """
        Get presigned URL for file access

        Args:
            file_hash: SHA256 hash of file
            expires_in: URL expiration time in seconds (default: 1 hour)

        Returns:
            Presigned URL for file access
        """
        try:
            key = self.get_file_path(file_hash)

            # Generate presigned URL
            url = self.s3_client.generate_presigned_url(
                'get_object',
                Params={
                    'Bucket': self.bucket,
                    'Key': key
                },
                ExpiresIn=expires_in
            )

            return url

        except self.ClientError as e:
            logger.error(f"Failed to generate presigned URL for {file_hash}: {e}")
            raise StorageError(f"Failed to generate URL: {e}")

    def get_storage_stats(self) -> dict:
        """
        Get storage statistics from S3

        Returns:
            Dictionary with storage stats
        """
        try:
            # List all objects with .sub extension
            paginator = self.s3_client.get_paginator('list_objects_v2')
            pages = paginator.paginate(Bucket=self.bucket, Prefix='')

            total_files = 0
            total_size = 0

            for page in pages:
                if 'Contents' in page:
                    for obj in page['Contents']:
                        if obj['Key'].endswith('.sub'):
                            total_files += 1
                            total_size += obj['Size']

            return {
                "total_files": total_files,
                "total_size_bytes": total_size,
                "total_size_mb": round(total_size / (1024 * 1024), 2),
                "bucket": self.bucket,
                "region": self.region
            }

        except self.ClientError as e:
            logger.error(f"Failed to get S3 storage stats: {e}")
            return {
                "error": str(e)
            }
