use git::rpc::{proto as p, proto::blob_service_client::BlobServiceClient};
use session::Session;

use crate::{AppService, error::AppError, git::rpc_err};

impl AppService {
    pub async fn git_blob_load(
        &self,
        ctx: &Session,
        wk_name: &str,
        repo_name: &str,
        oid: String,
        path: String,
    ) -> Result<p::BlobLoadResponse, AppError> {
        let repo = self.git_require_member(ctx, wk_name, repo_name).await?;
        let mut client = BlobServiceClient::new(self.git.clone());
        let resp = client
            .blob_load(tonic::Request::new(p::BlobLoadRequest {
                repo_id: repo.id.to_string(),
                id: Some(p::ObjectId { value: oid }),
                path,
            }))
            .await
            .map_err(rpc_err)?
            .into_inner();
        Ok(resp)
    }

    pub async fn git_blob_size(
        &self,
        ctx: &Session,
        wk_name: &str,
        repo_name: &str,
        oid: String,
        path: String,
    ) -> Result<p::BlobSizeResponse, AppError> {
        let repo = self.git_require_member(ctx, wk_name, repo_name).await?;
        let mut client = BlobServiceClient::new(self.git.clone());
        let resp = client
            .blob_size(tonic::Request::new(p::BlobSizeRequest {
                repo_id: repo.id.to_string(),
                id: Some(p::ObjectId { value: oid }),
                path,
            }))
            .await
            .map_err(rpc_err)?
            .into_inner();
        Ok(resp)
    }

    pub async fn git_blob_exists(
        &self,
        ctx: &Session,
        wk_name: &str,
        repo_name: &str,
        oid: String,
    ) -> Result<p::BlobExistsResponse, AppError> {
        let repo = self.git_require_member(ctx, wk_name, repo_name).await?;
        let mut client = BlobServiceClient::new(self.git.clone());
        let resp = client
            .blob_exists(tonic::Request::new(p::BlobExistsRequest {
                repo_id: repo.id.to_string(),
                id: Some(p::ObjectId { value: oid }),
            }))
            .await
            .map_err(rpc_err)?
            .into_inner();
        Ok(resp)
    }

    pub async fn git_blob_is_binary(
        &self,
        ctx: &Session,
        wk_name: &str,
        repo_name: &str,
        oid: String,
    ) -> Result<p::BlobIsBinaryResponse, AppError> {
        let repo = self.git_require_member(ctx, wk_name, repo_name).await?;
        let mut client = BlobServiceClient::new(self.git.clone());
        let resp = client
            .blob_is_binary(tonic::Request::new(p::BlobIsBinaryRequest {
                repo_id: repo.id.to_string(),
                id: Some(p::ObjectId { value: oid }),
            }))
            .await
            .map_err(rpc_err)?
            .into_inner();
        Ok(resp)
    }

    pub async fn git_blob_upload(
        &self,
        ctx: &Session,
        wk_name: &str,
        repo_name: &str,
        path: String,
        blob: Vec<u8>,
    ) -> Result<p::BlobUploadResponse, AppError> {
        let repo = self.git_require_admin(ctx, wk_name, repo_name).await?;
        let mut client = BlobServiceClient::new(self.git.clone());
        let resp = client
            .blob_upload(tonic::Request::new(p::BlobUploadRequest {
                repo_id: repo.id.to_string(),
                blob,
                path,
            }))
            .await
            .map_err(rpc_err)?
            .into_inner();
        self.queue_sync(repo.id).await;
        Ok(resp)
    }
}
