use git::rpc::{proto as p, proto::diff_service_client::DiffServiceClient};
use session::Session;

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

const MAX_GRPC_MSG: usize = 50 * 1024 * 1024; // 50MB

impl AppService {
    pub async fn git_diff_stats(
        &self,
        ctx: &Session,
        wk_name: &str,
        repo_name: &str,
        old_oid: String,
        new_oid: String,
        options: Option<p::DiffOptions>,
    ) -> Result<p::DiffStatsResponse, AppError> {
        let repo = self.git_require_member(ctx, wk_name, repo_name).await?;
        let mut client = DiffServiceClient::new(self.git.clone())
            .max_decoding_message_size(MAX_GRPC_MSG);
        let resp = client
            .diff_stats(tonic::Request::new(p::DiffStatsRequest {
                repo_id: repo.id.to_string(),
                old_oid: Some(p::ObjectId { value: old_oid }),
                new_oid: Some(p::ObjectId { value: new_oid }),
                options,
            }))
            .await
            .map_err(rpc_err)?
            .into_inner();
        Ok(resp)
    }

    pub async fn git_diff_patch(
        &self,
        ctx: &Session,
        wk_name: &str,
        repo_name: &str,
        old_oid: String,
        new_oid: String,
        options: Option<p::DiffOptions>,
    ) -> Result<p::DiffPatchResponse, AppError> {
        let repo = self.git_require_member(ctx, wk_name, repo_name).await?;
        let mut client = DiffServiceClient::new(self.git.clone())
            .max_decoding_message_size(MAX_GRPC_MSG);
        let resp = client
            .diff_patch(tonic::Request::new(p::DiffPatchRequest {
                repo_id: repo.id.to_string(),
                old_oid: Some(p::ObjectId { value: old_oid }),
                new_oid: Some(p::ObjectId { value: new_oid }),
                options,
            }))
            .await
            .map_err(rpc_err)?
            .into_inner();
        Ok(resp)
    }

    pub async fn git_diff_patch_side_by_side(
        &self,
        ctx: &Session,
        wk_name: &str,
        repo_name: &str,
        old_oid: String,
        new_oid: String,
        options: Option<p::DiffOptions>,
    ) -> Result<p::DiffPatchSideBySideResponse, AppError> {
        let repo = self.git_require_member(ctx, wk_name, repo_name).await?;
        let mut client = DiffServiceClient::new(self.git.clone())
            .max_decoding_message_size(MAX_GRPC_MSG);
        let resp = client
            .diff_patch_side_by_side(tonic::Request::new(
                p::DiffPatchSideBySideRequest {
                    repo_id: repo.id.to_string(),
                    old_oid: Some(p::ObjectId { value: old_oid }),
                    new_oid: Some(p::ObjectId { value: new_oid }),
                    options,
                },
            ))
            .await
            .map_err(rpc_err)?
            .into_inner();
        Ok(resp)
    }

    pub async fn git_diff_tree_to_tree(
        &self,
        ctx: &Session,
        wk_name: &str,
        repo_name: &str,
        old_tree: String,
        new_tree: String,
        options: Option<p::DiffOptions>,
    ) -> Result<p::DiffTreeToTreeResponse, AppError> {
        let repo = self.git_require_member(ctx, wk_name, repo_name).await?;
        let mut client = DiffServiceClient::new(self.git.clone())
            .max_decoding_message_size(MAX_GRPC_MSG);
        let resp = client
            .diff_tree_to_tree(tonic::Request::new(p::DiffTreeToTreeRequest {
                repo_id: repo.id.to_string(),
                old_tree: Some(p::ObjectId { value: old_tree }),
                new_tree: Some(p::ObjectId { value: new_tree }),
                options,
            }))
            .await
            .map_err(rpc_err)?
            .into_inner();
        Ok(resp)
    }

    pub async fn git_diff_index_to_tree(
        &self,
        ctx: &Session,
        wk_name: &str,
        repo_name: &str,
        tree_oid: String,
        options: Option<p::DiffOptions>,
    ) -> Result<p::DiffIndexToTreeResponse, AppError> {
        let repo = self.git_require_member(ctx, wk_name, repo_name).await?;
        let mut client = DiffServiceClient::new(self.git.clone())
            .max_decoding_message_size(MAX_GRPC_MSG);
        let resp = client
            .diff_index_to_tree(tonic::Request::new(
                p::DiffIndexToTreeRequest {
                    repo_id: repo.id.to_string(),
                    tree_oid: Some(p::ObjectId { value: tree_oid }),
                    options,
                },
            ))
            .await
            .map_err(rpc_err)?
            .into_inner();
        Ok(resp)
    }
}
