// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.
// Modifications Copyright 2022 PingCAP, Inc.
// #[PerformanceCriticalPath]
use crossbeam::channel::TrySendError;
use kvproto::{raft_cmdpb::RaftCmdRequest, raft_serverpb::RaftMessage};

use crate::{
    DiscardReason, Error as RaftStoreError, Result as RaftStoreResult,
    store::{Callback, PeerMsg, RaftCmdExtraOpts, SignificantMsg, SignificantRouter},
};

/// Routes messages to the raftstore.
pub trait RaftStoreRouter: SignificantRouter + Send + Clone {
    /// Sends RaftMessage to local store.
    fn send_raft_msg(&self, msg: RaftMessage) -> RaftStoreResult<()>;

    /// Broadcast a message generated by `msg_gen` to all Raft groups.
    fn broadcast_normal(&self, msg_gen: impl FnMut() -> PeerMsg);

    /// Sends RaftCmdRequest to local store.
    fn send_command(
        &self,
        _req: RaftCmdRequest,
        _cb: Callback,
        _extra_opts: RaftCmdExtraOpts,
    ) -> RaftStoreResult<()> {
        unimplemented!()
    }

    /// Reports the peer being unreachable to the Region.
    fn report_unreachable(&self, _region_id: u64, _to_peer_id: u64) -> RaftStoreResult<()> {
        unimplemented!()
    }

    /// Report a `StoreResolved` event to all Raft groups.
    fn report_resolved(&self, store_id: u64, group_id: u64) {
        self.broadcast_normal(|| {
            PeerMsg::SignificantMsg(SignificantMsg::StoreResolved { store_id, group_id })
        })
    }
}

#[inline]
pub fn handle_send_error<T>(region_id: u64, e: TrySendError<T>) -> RaftStoreError {
    match e {
        TrySendError::Full(_) => RaftStoreError::Transport(DiscardReason::Full),
        TrySendError::Disconnected(_) => RaftStoreError::RegionNotFound(region_id),
    }
}
