from __future__ import annotations
import shutil
from pathlib import Path
from urllib.parse import quote
import boto3
from botocore.client import Config
from app.core.config import settings

class ObjectStorage:
    def __init__(self):
        self.backend = (settings.storage_backend or 'local').lower()
        self.bucket = settings.s3_bucket
        self.local_root = Path(settings.local_storage_path).resolve()
        self.local_root.mkdir(parents=True, exist_ok=True)
        self.client = None
        if self.backend == 's3':
            if not settings.s3_endpoint:
                raise RuntimeError('S3_ENDPOINT não configurado')
            self.client = boto3.client('s3', endpoint_url=settings.s3_endpoint,
                aws_access_key_id=settings.s3_access_key, aws_secret_access_key=settings.s3_secret_key,
                config=Config(signature_version='s3v4'), use_ssl=settings.s3_secure)

    def ensure_bucket(self):
        if self.backend != 's3':
            self.local_root.mkdir(parents=True, exist_ok=True); return
        buckets = [b['Name'] for b in self.client.list_buckets().get('Buckets', [])]
        if self.bucket not in buckets: self.client.create_bucket(Bucket=self.bucket)

    def tenant_key(self, tenant_id: str, object_key: str) -> str:
        clean = object_key.lstrip('/').replace('..', '_')
        return f'tenants/{tenant_id}/{clean}'

    def _local_path(self, object_key: str) -> Path:
        clean = object_key.lstrip('/').replace('..', '_')
        target = (self.local_root / clean).resolve()
        if self.local_root not in target.parents and target != self.local_root:
            raise ValueError('Caminho de armazenamento inválido')
        return target

    def upload_for_tenant(self, tenant_id: str, local_path: str, object_key: str):
        return self.upload(local_path, self.tenant_key(tenant_id, object_key))

    def presigned_get_for_tenant(self, tenant_id: str, object_key: str, expires_seconds: int = 300) -> str:
        return self.presigned_get(self.tenant_key(tenant_id, object_key), expires_seconds)

    def upload(self, local_path: str, object_key: str):
        self.ensure_bucket()
        if self.backend == 'local':
            target = self._local_path(object_key); target.parent.mkdir(parents=True, exist_ok=True)
            shutil.copy2(local_path, target); return str(target)
        self.client.upload_file(local_path, self.bucket, object_key)

    def download(self, object_key: str, local_path: str):
        self.ensure_bucket()
        if self.backend == 'local':
            source = self._local_path(object_key); Path(local_path).parent.mkdir(parents=True, exist_ok=True)
            shutil.copy2(source, local_path); return
        self.client.download_file(self.bucket, object_key, local_path)

    def presigned_get(self, object_key: str, expires_seconds: int = 300) -> str:
        if self.backend == 'local':
            return f"/api/v028/local-files/{quote(object_key, safe='/')}"
        return self.client.generate_presigned_url('get_object', Params={'Bucket': self.bucket,'Key':object_key}, ExpiresIn=expires_seconds)
