use crate::error::Result;
use async_trait::async_trait;

#[async_trait]
pub trait StoragePort: Send + Sync {
    /// Uploads an encrypted file payload and returns the storage reference (e.g., URL or path)
    async fn upload_file(&self, payload: &[u8], owner_id: Option<&str>) -> Result<String>;
    
    /// Downloads an encrypted file payload given a storage reference
    async fn download_file(&self, storage_ref: &str) -> Result<Vec<u8>>;
    
    /// Deletes a file given its storage reference
    async fn delete_file(&self, storage_ref: &str) -> Result<()>;

    /// Generates a pre-signed URL for downloading a file
    async fn generate_presigned_url(&self, storage_ref: &str, expires_in: std::time::Duration) -> Result<String>;

    /// Initializes a multipart upload and returns an upload ID
    async fn create_multipart_upload(&self, file_name: &str, owner_id: Option<&str>) -> Result<String>;

    /// Generates a pre-signed URL for uploading a specific part of a multipart upload
    async fn generate_presigned_part_url(&self, storage_ref: &str, upload_id: &str, part_number: i32) -> Result<String>;

    /// Completes a multipart upload
    async fn complete_multipart_upload(&self, storage_ref: &str, upload_id: &str, parts: Vec<(i32, String)>) -> Result<()>;
}

#[async_trait]
impl<T: StoragePort + ?Sized + Send + Sync> StoragePort for std::sync::Arc<T> {
    async fn upload_file(&self, payload: &[u8], owner_id: Option<&str>) -> Result<String> {
        self.as_ref().upload_file(payload, owner_id).await
    }
    async fn download_file(&self, storage_ref: &str) -> Result<Vec<u8>> {
        self.as_ref().download_file(storage_ref).await
    }
    async fn delete_file(&self, storage_ref: &str) -> Result<()> {
        self.as_ref().delete_file(storage_ref).await
    }
    async fn generate_presigned_url(&self, storage_ref: &str, expires_in: std::time::Duration) -> Result<String> {
        self.as_ref().generate_presigned_url(storage_ref, expires_in).await
    }
    async fn create_multipart_upload(&self, file_name: &str, owner_id: Option<&str>) -> Result<String> {
        self.as_ref().create_multipart_upload(file_name, owner_id).await
    }
    async fn generate_presigned_part_url(&self, storage_ref: &str, upload_id: &str, part_number: i32) -> Result<String> {
        self.as_ref().generate_presigned_part_url(storage_ref, upload_id, part_number).await
    }
    async fn complete_multipart_upload(&self, storage_ref: &str, upload_id: &str, parts: Vec<(i32, String)>) -> Result<()> {
        self.as_ref().complete_multipart_upload(storage_ref, upload_id, parts).await
    }
}
