use git::rpc::{proto as p, proto::commit_service_client::CommitServiceClient};
use session::Session;

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

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

    pub async fn git_commit_history(
        &self,
        ctx: &Session,
        wk_name: &str,
        repo_name: &str,
        limit: u64,
        skip: u64,
        sort: i32,
        branch: Option<String>,
    ) -> Result<p::CommitHistoryResponse, AppError> {
        let repo = self.git_require_member(ctx, wk_name, repo_name).await?;
        let mut client = CommitServiceClient::new(self.git.clone());
        let resp = client
            .commit_history(tonic::Request::new(p::CommitHistoryRequest {
                repo_id: repo.id.to_string(),
                limit,
                skip,
                sort,
                branch,
            }))
            .await
            .map_err(rpc_err)?
            .into_inner();
        Ok(resp)
    }

    pub async fn git_commit_summary(
        &self,
        ctx: &Session,
        wk_name: &str,
        repo_name: &str,
    ) -> Result<p::CommitSummaryResponse, AppError> {
        let repo = self.git_require_member(ctx, wk_name, repo_name).await?;
        let mut client = CommitServiceClient::new(self.git.clone());
        let resp = client
            .commit_summary(tonic::Request::new(p::CommitSummaryRequest {
                repo_id: repo.id.to_string(),
            }))
            .await
            .map_err(rpc_err)?
            .into_inner();
        Ok(resp)
    }

    pub async fn git_commit_walk(
        &self,
        ctx: &Session,
        wk_name: &str,
        repo_name: &str,
        params: p::CommitWalkParams,
    ) -> Result<p::CommitWalkResponse, AppError> {
        let repo = self.git_require_member(ctx, wk_name, repo_name).await?;
        let mut client = CommitServiceClient::new(self.git.clone());
        let resp = client
            .commit_walk(tonic::Request::new(p::CommitWalkRequest {
                repo_id: repo.id.to_string(),
                params: Some(params),
            }))
            .await
            .map_err(rpc_err)?
            .into_inner();
        Ok(resp)
    }

    pub async fn git_commit_refs(
        &self,
        ctx: &Session,
        wk_name: &str,
        repo_name: &str,
    ) -> Result<p::CommitRefsResponse, AppError> {
        let repo = self.git_require_member(ctx, wk_name, repo_name).await?;
        let mut client = CommitServiceClient::new(self.git.clone());
        let resp = client
            .commit_refs(tonic::Request::new(p::CommitRefsRequest {
                repo_id: repo.id.to_string(),
            }))
            .await
            .map_err(rpc_err)?
            .into_inner();
        Ok(resp)
    }

    pub async fn git_commit_prefix(
        &self,
        ctx: &Session,
        wk_name: &str,
        repo_name: &str,
        prefix: String,
    ) -> Result<p::CommitPrefixResponse, AppError> {
        let repo = self.git_require_member(ctx, wk_name, repo_name).await?;
        let mut client = CommitServiceClient::new(self.git.clone());
        let resp = client
            .commit_prefix(tonic::Request::new(p::CommitPrefixRequest {
                repo_id: repo.id.to_string(),
                prefix,
            }))
            .await
            .map_err(rpc_err)?
            .into_inner();
        Ok(resp)
    }

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

    pub async fn git_cherry_pick(
        &self,
        ctx: &Session,
        wk_name: &str,
        repo_name: &str,
        params: p::CommitCherryPickParams,
    ) -> Result<p::CherryPickResponse, AppError> {
        let repo = self.git_require_admin(ctx, wk_name, repo_name).await?;
        let mut client = CommitServiceClient::new(self.git.clone());
        let resp = client
            .cherry_pick(tonic::Request::new(p::CherryPickRequest {
                repo_id: repo.id.to_string(),
                params: Some(params),
            }))
            .await
            .map_err(rpc_err)?
            .into_inner();
        self.queue_sync(repo.id).await;
        Ok(resp)
    }

    pub async fn git_cherry_pick_sequence(
        &self,
        ctx: &Session,
        wk_name: &str,
        repo_name: &str,
        params: p::CommitCherryPickSequence,
    ) -> Result<p::CherryPickSequenceResponse, AppError> {
        let repo = self.git_require_admin(ctx, wk_name, repo_name).await?;
        let mut client = CommitServiceClient::new(self.git.clone());
        let resp = client
            .cherry_pick_sequence(tonic::Request::new(
                p::CherryPickSequenceRequest {
                    repo_id: repo.id.to_string(),
                    params: Some(params),
                },
            ))
            .await
            .map_err(rpc_err)?
            .into_inner();
        self.queue_sync(repo.id).await;
        Ok(resp)
    }
}
