use git::rpc::{proto as p, proto::tag_service_client::TagServiceClient};
use session::Session;

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

impl AppService {
    pub async fn git_tag_list(
        &self,
        ctx: &Session,
        wk_name: &str,
        repo_name: &str,
        pagination: Pagination,
    ) -> Result<p::TagListResponse, AppError> {
        let repo = self.git_require_member(ctx, wk_name, repo_name).await?;
        let mut client = TagServiceClient::new(self.git.clone());
        let mut resp = client
            .tag_list(tonic::Request::new(p::TagListRequest {
                repo_id: repo.id.to_string(),
            }))
            .await
            .map_err(rpc_err)?
            .into_inner();

        let offset = pagination.offset() as usize;
        let limit = pagination.limit() as usize;
        if offset > 0 || resp.tags.len() > limit {
            let start = offset.min(resp.tags.len());
            let end = (start + limit).min(resp.tags.len());
            resp.tags = resp.tags.drain(start..end).collect();
        }
        Ok(resp)
    }

    pub async fn git_tag_info(
        &self,
        ctx: &Session,
        wk_name: &str,
        repo_name: &str,
        name: String,
    ) -> Result<p::TagInfoResponse, AppError> {
        let repo = self.git_require_member(ctx, wk_name, repo_name).await?;
        let mut client = TagServiceClient::new(self.git.clone());
        let resp = client
            .tag_info(tonic::Request::new(p::TagInfoRequest {
                repo_id: repo.id.to_string(),
                name,
            }))
            .await
            .map_err(rpc_err)?
            .into_inner();
        Ok(resp)
    }

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

    pub async fn git_tag_init(
        &self,
        ctx: &Session,
        wk_name: &str,
        repo_name: &str,
        params: p::TagInitParams,
    ) -> Result<p::TagInitResponse, AppError> {
        let repo = self.git_require_admin(ctx, wk_name, repo_name).await?;
        let mut client = TagServiceClient::new(self.git.clone());
        let resp = client
            .tag_init(tonic::Request::new(p::TagInitRequest {
                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_tag_delete(
        &self,
        ctx: &Session,
        wk_name: &str,
        repo_name: &str,
        params: p::TagDeleteParams,
    ) -> Result<p::TagDeleteResponse, AppError> {
        let repo = self.git_require_admin(ctx, wk_name, repo_name).await?;
        let mut client = TagServiceClient::new(self.git.clone());
        let resp = client
            .tag_delete(tonic::Request::new(p::TagDeleteRequest {
                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_tag_rename(
        &self,
        ctx: &Session,
        wk_name: &str,
        repo_name: &str,
        params: p::TagRenameParams,
    ) -> Result<p::TagRenameResponse, AppError> {
        let repo = self.git_require_admin(ctx, wk_name, repo_name).await?;
        let mut client = TagServiceClient::new(self.git.clone());
        let resp = client
            .tag_rename(tonic::Request::new(p::TagRenameRequest {
                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_tag_update_message(
        &self,
        ctx: &Session,
        wk_name: &str,
        repo_name: &str,
        params: p::TagUpdateMessageParams,
    ) -> Result<p::TagUpdateMessageResponse, AppError> {
        let repo = self.git_require_admin(ctx, wk_name, repo_name).await?;
        let mut client = TagServiceClient::new(self.git.clone());
        let resp = client
            .tag_update_message(tonic::Request::new(
                p::TagUpdateMessageRequest {
                    repo_id: repo.id.to_string(),
                    params: Some(params),
                },
            ))
            .await
            .map_err(rpc_err)?
            .into_inner();
        self.queue_sync(repo.id).await;
        Ok(resp)
    }
}
