// Copyright 2024 RustFS Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Used by test_distributed_lock_4_nodes_grpc in lock.rs
#![allow(dead_code)]

use bytes::Bytes;
use futures::Stream;
use rustfs_lock::{LockClient, LockRequest};
use rustfs_protos::{
    models::PingBodyBuilder,
    proto_gen::node_service::{
        BatchGenerallyLockRequest, BatchGenerallyLockResponse, BatchReadVersionRequest, BatchReadVersionResponse,
        GenerallyLockRequest, GenerallyLockResponse, GenerallyLockResult, PingRequest, PingResponse,
        ScannerPublicationLeaseReleaseRequest, ScannerPublicationLeaseReleaseResponse, ScannerPublicationLeaseRequest,
        ScannerPublicationLeaseResponse, SnapshotLeaseMutationResponse, SnapshotLeaseReleaseRequest, SnapshotLeaseRenewRequest,
        SnapshotLeaseRequest, SnapshotLeaseResponse, node_service_server::NodeService,
    },
};
use std::pin::Pin;
use std::sync::Arc;
use tokio::net::TcpListener;
use tokio_stream::wrappers::TcpListenerStream;
use tonic::{Request, Response, Status};
use tracing::debug;

type ResponseStream<T> = Pin<Box<dyn Stream<Item = Result<T, Status>> + Send>>;

fn lock_result_from_response(response: rustfs_lock::LockResponse) -> GenerallyLockResult {
    GenerallyLockResult {
        success: response.success,
        error_info: response.error,
        lock_info: response.lock_info.and_then(|info| serde_json::to_string(&info).ok()),
    }
}

fn lock_result_from_error(error: impl Into<String>) -> GenerallyLockResult {
    GenerallyLockResult {
        success: false,
        error_info: Some(error.into()),
        lock_info: None,
    }
}

fn lock_result_from_release(lock_id: &rustfs_lock::LockId, success: bool) -> GenerallyLockResult {
    if success {
        GenerallyLockResult {
            success: true,
            error_info: None,
            lock_info: None,
        }
    } else {
        lock_result_from_error(format!("lock not found for release: {lock_id}"))
    }
}

/// Minimal NodeService implementation that only supports Lock RPCs
/// Used for testing distributed lock scenarios with real gRPC
#[derive(Debug)]
pub struct MinimalLockNodeService {
    lock_client: Arc<dyn LockClient>,
}

impl MinimalLockNodeService {
    pub fn new(lock_client: Arc<dyn LockClient>) -> Self {
        Self { lock_client }
    }
}

#[tonic::async_trait]
impl NodeService for MinimalLockNodeService {
    async fn ping(&self, _request: Request<PingRequest>) -> Result<Response<PingResponse>, Status> {
        debug!("MinimalLockNodeService: PING");

        let mut fbb = flatbuffers::FlatBufferBuilder::new();
        let payload = fbb.create_vector(b"pong");

        let mut builder = PingBodyBuilder::new(&mut fbb);
        builder.add_payload(payload);
        let root = builder.finish();
        fbb.finish(root, None);

        let finished_data = fbb.finished_data();

        Ok(Response::new(PingResponse {
            version: 1,
            body: Bytes::copy_from_slice(finished_data),
        }))
    }

    async fn batch_read_version(
        &self,
        _request: Request<BatchReadVersionRequest>,
    ) -> Result<Response<BatchReadVersionResponse>, Status> {
        Err(Status::unimplemented("MinimalLockNodeService only supports lock RPCs"))
    }

    async fn acquire_snapshot_lease(
        &self,
        _request: Request<SnapshotLeaseRequest>,
    ) -> Result<Response<SnapshotLeaseResponse>, Status> {
        Err(Status::unimplemented("MinimalLockNodeService only supports lock RPCs"))
    }

    async fn renew_snapshot_lease(
        &self,
        _request: Request<SnapshotLeaseRenewRequest>,
    ) -> Result<Response<SnapshotLeaseResponse>, Status> {
        Err(Status::unimplemented("MinimalLockNodeService only supports lock RPCs"))
    }

    async fn release_snapshot_lease(
        &self,
        _request: Request<SnapshotLeaseReleaseRequest>,
    ) -> Result<Response<SnapshotLeaseMutationResponse>, Status> {
        Err(Status::unimplemented("MinimalLockNodeService only supports lock RPCs"))
    }

    async fn acquire_scanner_publication_lease(
        &self,
        _request: Request<ScannerPublicationLeaseRequest>,
    ) -> Result<Response<ScannerPublicationLeaseResponse>, Status> {
        Err(Status::unimplemented("MinimalLockNodeService only supports lock RPCs"))
    }

    async fn release_scanner_publication_lease(
        &self,
        _request: Request<ScannerPublicationLeaseReleaseRequest>,
    ) -> Result<Response<ScannerPublicationLeaseReleaseResponse>, Status> {
        Err(Status::unimplemented("MinimalLockNodeService only supports lock RPCs"))
    }

    async fn lock(&self, request: Request<GenerallyLockRequest>) -> Result<Response<GenerallyLockResponse>, Status> {
        let request = request.into_inner();
        let args: LockRequest = match serde_json::from_str(&request.args) {
            Ok(args) => args,
            Err(err) => {
                return Ok(Response::new(GenerallyLockResponse {
                    success: false,
                    error_info: Some(format!("can not decode args, err: {err}")),
                    lock_info: None,
                }));
            }
        };

        match self.lock_client.acquire_lock(&args).await {
            Ok(result) => {
                let lock_info_json = result.lock_info.as_ref().and_then(|info| serde_json::to_string(info).ok());
                Ok(Response::new(GenerallyLockResponse {
                    success: result.success,
                    error_info: result.error,
                    lock_info: lock_info_json,
                }))
            }
            Err(err) => Ok(Response::new(GenerallyLockResponse {
                success: false,
                error_info: Some(format!(
                    "can not lock, resource: {0}, owner: {1}, err: {2}",
                    args.resource, args.owner, err
                )),
                lock_info: None,
            })),
        }
    }

    async fn un_lock(&self, request: Request<GenerallyLockRequest>) -> Result<Response<GenerallyLockResponse>, Status> {
        let request = request.into_inner();
        let args: LockRequest = match serde_json::from_str(&request.args) {
            Ok(args) => args,
            Err(err) => {
                return Ok(Response::new(GenerallyLockResponse {
                    success: false,
                    error_info: Some(format!("can not decode args, err: {err}")),
                    lock_info: None,
                }));
            }
        };

        match self.lock_client.release(&args.lock_id).await {
            Ok(success) => {
                let result = lock_result_from_release(&args.lock_id, success);
                Ok(Response::new(GenerallyLockResponse {
                    success: result.success,
                    error_info: result.error_info,
                    lock_info: None,
                }))
            }
            Err(err) => Ok(Response::new(GenerallyLockResponse {
                success: false,
                error_info: Some(format!(
                    "can not unlock, resource: {0}, owner: {1}, err: {2}",
                    args.resource, args.owner, err
                )),
                lock_info: None,
            })),
        }
    }

    async fn force_un_lock(&self, request: Request<GenerallyLockRequest>) -> Result<Response<GenerallyLockResponse>, Status> {
        let request = request.into_inner();
        let args: LockRequest = match serde_json::from_str(&request.args) {
            Ok(args) => args,
            Err(err) => {
                return Ok(Response::new(GenerallyLockResponse {
                    success: false,
                    error_info: Some(format!("can not decode args, err: {err}")),
                    lock_info: None,
                }));
            }
        };

        match self.lock_client.force_release(&args.lock_id).await {
            Ok(success) => {
                let result = lock_result_from_release(&args.lock_id, success);
                Ok(Response::new(GenerallyLockResponse {
                    success: result.success,
                    error_info: result.error_info,
                    lock_info: None,
                }))
            }
            Err(err) => Ok(Response::new(GenerallyLockResponse {
                success: false,
                error_info: Some(format!(
                    "can not force_unlock, resource: {0}, owner: {1}, err: {2}",
                    args.resource, args.owner, err
                )),
                lock_info: None,
            })),
        }
    }

    async fn refresh(&self, request: Request<GenerallyLockRequest>) -> Result<Response<GenerallyLockResponse>, Status> {
        let request = request.into_inner();
        let args: LockRequest = match serde_json::from_str(&request.args) {
            Ok(args) => args,
            Err(err) => {
                return Ok(Response::new(GenerallyLockResponse {
                    success: false,
                    error_info: Some(format!("can not decode args, err: {err}")),
                    lock_info: None,
                }));
            }
        };

        match self.lock_client.refresh(&args.lock_id).await {
            Ok(success) => Ok(Response::new(GenerallyLockResponse {
                success,
                error_info: None,
                lock_info: None,
            })),
            Err(err) => Ok(Response::new(GenerallyLockResponse {
                success: false,
                error_info: Some(format!("can not refresh, err: {err}")),
                lock_info: None,
            })),
        }
    }

    async fn lock_batch(
        &self,
        request: Request<BatchGenerallyLockRequest>,
    ) -> Result<Response<BatchGenerallyLockResponse>, Status> {
        let request = request.into_inner();
        let mut results = vec![lock_result_from_error("request was not processed"); request.args.len()];
        let mut valid_requests = Vec::with_capacity(request.args.len());
        let mut valid_indices = Vec::with_capacity(request.args.len());

        for (idx, arg) in request.args.iter().enumerate() {
            match serde_json::from_str::<LockRequest>(arg) {
                Ok(args) => {
                    valid_requests.push(args);
                    valid_indices.push(idx);
                }
                Err(err) => {
                    results[idx] = lock_result_from_error(format!("can not decode args, err: {err}"));
                }
            }
        }

        if !valid_requests.is_empty() {
            match self.lock_client.acquire_locks_batch(&valid_requests).await {
                Ok(batch_results) => {
                    for (result_idx, response) in batch_results.into_iter().enumerate() {
                        if let Some(request_idx) = valid_indices.get(result_idx) {
                            results[*request_idx] = lock_result_from_response(response);
                        }
                    }
                }
                Err(err) => {
                    for request_idx in valid_indices {
                        results[request_idx] = lock_result_from_error(format!("can not batch lock, err: {err}"));
                    }
                }
            }
        }

        Ok(Response::new(BatchGenerallyLockResponse { results }))
    }

    async fn un_lock_batch(
        &self,
        request: Request<BatchGenerallyLockRequest>,
    ) -> Result<Response<BatchGenerallyLockResponse>, Status> {
        let request = request.into_inner();
        let mut results = vec![lock_result_from_error("request was not processed"); request.args.len()];
        let mut lock_ids = Vec::with_capacity(request.args.len());
        let mut valid_indices = Vec::with_capacity(request.args.len());

        for (idx, arg) in request.args.iter().enumerate() {
            match serde_json::from_str::<LockRequest>(arg) {
                Ok(args) => {
                    lock_ids.push(args.lock_id);
                    valid_indices.push(idx);
                }
                Err(err) => {
                    results[idx] = lock_result_from_error(format!("can not decode args, err: {err}"));
                }
            }
        }

        if !lock_ids.is_empty() {
            match self.lock_client.release_locks_batch(&lock_ids).await {
                Ok(batch_results) => {
                    for (result_idx, success) in batch_results.into_iter().enumerate() {
                        if let Some(request_idx) = valid_indices.get(result_idx) {
                            results[*request_idx] = match lock_ids.get(result_idx) {
                                Some(lock_id) => lock_result_from_release(lock_id, success),
                                None => lock_result_from_error(format!("unlock response index out of range: {result_idx}")),
                            };
                        }
                    }
                }
                Err(err) => {
                    for request_idx in valid_indices {
                        results[request_idx] = lock_result_from_error(format!("can not batch unlock, err: {err}"));
                    }
                }
            }
        }

        Ok(Response::new(BatchGenerallyLockResponse { results }))
    }

    // All other methods return unimplemented
    async fn heal_bucket(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::HealBucketRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::HealBucketResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn list_bucket(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::ListBucketRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::ListBucketResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn make_bucket(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::MakeBucketRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::MakeBucketResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn get_bucket_info(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::GetBucketInfoRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::GetBucketInfoResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn delete_bucket(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::DeleteBucketRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::DeleteBucketResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn read_all(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::ReadAllRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::ReadAllResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn write_all(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::WriteAllRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::WriteAllResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn delete(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::DeleteRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::DeleteResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn verify_file(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::VerifyFileRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::VerifyFileResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn read_parts(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::ReadPartsRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::ReadPartsResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn check_parts(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::CheckPartsRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::CheckPartsResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn rename_part(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::RenamePartRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::RenamePartResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn prepare_part_transaction(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::PreparePartTransactionRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::PreparePartTransactionResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn settle_part_transaction(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::SettlePartTransactionRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::SettlePartTransactionResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn rename_file(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::RenameFileRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::RenameFileResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn write(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::WriteRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::WriteResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    type WriteStreamStream = ResponseStream<rustfs_protos::proto_gen::node_service::WriteResponse>;

    async fn write_stream(
        &self,
        _request: Request<tonic::Streaming<rustfs_protos::proto_gen::node_service::WriteRequest>>,
    ) -> Result<Response<Self::WriteStreamStream>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    type ReadAtStream = ResponseStream<rustfs_protos::proto_gen::node_service::ReadAtResponse>;

    async fn read_at(
        &self,
        _request: Request<tonic::Streaming<rustfs_protos::proto_gen::node_service::ReadAtRequest>>,
    ) -> Result<Response<Self::ReadAtStream>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn list_dir(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::ListDirRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::ListDirResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    type WalkDirStream = ResponseStream<rustfs_protos::proto_gen::node_service::WalkDirResponse>;

    async fn walk_dir(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::WalkDirRequest>,
    ) -> Result<Response<Self::WalkDirStream>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn rename_data(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::RenameDataRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::RenameDataResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn make_volumes(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::MakeVolumesRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::MakeVolumesResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn make_volume(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::MakeVolumeRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::MakeVolumeResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn list_volumes(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::ListVolumesRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::ListVolumesResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn stat_volume(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::StatVolumeRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::StatVolumeResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn delete_paths(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::DeletePathsRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::DeletePathsResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn update_metadata(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::UpdateMetadataRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::UpdateMetadataResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn read_metadata(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::ReadMetadataRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::ReadMetadataResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn write_metadata(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::WriteMetadataRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::WriteMetadataResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn read_version(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::ReadVersionRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::ReadVersionResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn read_xl(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::ReadXlRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::ReadXlResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn delete_version(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::DeleteVersionRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::DeleteVersionResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn delete_versions(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::DeleteVersionsRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::DeleteVersionsResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn read_multiple(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::ReadMultipleRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::ReadMultipleResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn delete_volume(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::DeleteVolumeRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::DeleteVolumeResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn disk_info(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::DiskInfoRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::DiskInfoResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn local_storage_info(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::LocalStorageInfoRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::LocalStorageInfoResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn server_info(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::ServerInfoRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::ServerInfoResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn get_cpus(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::GetCpusRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::GetCpusResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn get_net_info(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::GetNetInfoRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::GetNetInfoResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn get_partitions(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::GetPartitionsRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::GetPartitionsResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn get_os_info(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::GetOsInfoRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::GetOsInfoResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn get_se_linux_info(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::GetSeLinuxInfoRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::GetSeLinuxInfoResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn get_sys_config(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::GetSysConfigRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::GetSysConfigResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn get_sys_errors(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::GetSysErrorsRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::GetSysErrorsResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn get_mem_info(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::GetMemInfoRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::GetMemInfoResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn get_proc_info(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::GetProcInfoRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::GetProcInfoResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn load_bucket_metadata(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::LoadBucketMetadataRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::LoadBucketMetadataResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn load_policy(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::LoadPolicyRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::LoadPolicyResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn load_group(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::LoadGroupRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::LoadGroupResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn load_policy_mapping(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::LoadPolicyMappingRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::LoadPolicyMappingResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn load_rebalance_meta(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::LoadRebalanceMetaRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::LoadRebalanceMetaResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn start_decommission(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::StartDecommissionRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::StartDecommissionResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn cancel_decommission(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::CancelDecommissionRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::CancelDecommissionResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn clear_decommission(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::ClearDecommissionRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::ClearDecommissionResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn get_metrics(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::GetMetricsRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::GetMetricsResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn get_live_events(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::GetLiveEventsRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::GetLiveEventsResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn start_profiling(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::StartProfilingRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::StartProfilingResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn download_profile_data(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::DownloadProfileDataRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::DownloadProfileDataResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn get_bucket_stats(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::GetBucketStatsDataRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::GetBucketStatsDataResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn get_sr_metrics(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::GetSrMetricsDataRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::GetSrMetricsDataResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn get_all_bucket_stats(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::GetAllBucketStatsRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::GetAllBucketStatsResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn delete_bucket_metadata(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::DeleteBucketMetadataRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::DeleteBucketMetadataResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn delete_policy(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::DeletePolicyRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::DeletePolicyResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn delete_user(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::DeleteUserRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::DeleteUserResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn delete_service_account(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::DeleteServiceAccountRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::DeleteServiceAccountResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn load_user(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::LoadUserRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::LoadUserResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn load_service_account(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::LoadServiceAccountRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::LoadServiceAccountResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn reload_site_replication_config(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::ReloadSiteReplicationConfigRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::ReloadSiteReplicationConfigResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn signal_service(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::SignalServiceRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::SignalServiceResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn scanner_activity(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::ScannerActivityRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::ScannerActivityResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn background_heal_status(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::BackgroundHealStatusRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::BackgroundHealStatusResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn replacement_recovery_status(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::ReplacementRecoveryStatusRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::ReplacementRecoveryStatusResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn get_metacache_listing(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::GetMetacacheListingRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::GetMetacacheListingResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn update_metacache_listing(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::UpdateMetacacheListingRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::UpdateMetacacheListingResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn reload_pool_meta(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::ReloadPoolMetaRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::ReloadPoolMetaResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn stop_rebalance(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::StopRebalanceRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::StopRebalanceResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }

    async fn load_transition_tier_config(
        &self,
        _request: Request<rustfs_protos::proto_gen::node_service::LoadTransitionTierConfigRequest>,
    ) -> Result<Response<rustfs_protos::proto_gen::node_service::LoadTransitionTierConfigResponse>, Status> {
        Err(Status::unimplemented("lock-only test server"))
    }
}

/// Spawn a gRPC lock server on a random port
/// Returns the address and a shutdown handle
pub async fn spawn_lock_server(
    lock_client: Arc<dyn LockClient>,
) -> std::result::Result<(String, tokio::task::JoinHandle<()>), Box<dyn std::error::Error>> {
    let listener = TcpListener::bind("127.0.0.1:0").await?;
    let addr = listener.local_addr()?;
    let addr_str = format!("http://127.0.0.1:{}", addr.port());

    let service = MinimalLockNodeService::new(lock_client);
    let server = tonic::transport::Server::builder()
        .add_service(rustfs_protos::proto_gen::node_service::node_service_server::NodeServiceServer::new(
            service,
        ))
        .serve_with_incoming(TcpListenerStream::new(listener));

    let handle = tokio::spawn(async move {
        if let Err(e) = server.await {
            eprintln!("gRPC server error: {}", e);
        }
    });

    Ok((addr_str, handle))
}
