#![warn(missing_docs)]
use common_runtime::{AccountId, Balance, Block, BlockNumber, Hash, Index};
use jsonrpsee::RpcModule;
use sc_consensus_babe::{BabeApi, BabeWorkerHandle};
use sc_consensus_grandpa::{
    self, FinalityProofProvider, GrandpaJustificationStream, SharedAuthoritySet, SharedVoterState,
};
use sc_rpc::SubscriptionTaskExecutor;
use sc_transaction_pool_api::TransactionPool;
use sp_api::ProvideRuntimeApi;
use sp_block_builder::BlockBuilder;
use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata};
use sp_consensus::SelectChain;
use sp_keystore::KeystorePtr;
use std::sync::Arc;
#[derive(Clone)]
pub struct BabeDeps {
    pub babe_worker_handle: BabeWorkerHandle<Block>,
    pub keystore: KeystorePtr,
}
#[derive(Clone)]
pub struct GrandpaDeps<B> {
    pub shared_voter_state: SharedVoterState,
    pub shared_authority_set: SharedAuthoritySet<Hash, BlockNumber>,
    pub justification_stream: GrandpaJustificationStream<Block>,
    pub subscription_executor: SubscriptionTaskExecutor,
    pub finality_provider: Arc<FinalityProofProvider<B, Block>>,
}
pub struct FullDeps<C, P, SC, B> {
    pub client: Arc<C>,
    pub pool: Arc<P>,
    pub select_chain: SC,
    pub command_sink_opt: Option<
        futures::channel::mpsc::Sender<sc_consensus_manual_seal::EngineCommand<sp_core::H256>>,
    >,
    pub babe: Option<BabeDeps>,
    pub grandpa: GrandpaDeps<B>,
}
pub fn create_full<C, P, SC, B>(
    deps: FullDeps<C, P, SC, B>,
) -> Result<RpcModule<()>, Box<dyn std::error::Error + Send + Sync>>
where
    C: ProvideRuntimeApi<Block>,
    C: HeaderBackend<Block> + HeaderMetadata<Block, Error = BlockChainError> + 'static,
    C: Send + Sync + 'static,
    C::Api: substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>,
    C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance>,
    C::Api: BabeApi<Block>,
    C::Api: BlockBuilder<Block>,
    P: TransactionPool + 'static,
    SC: SelectChain<Block> + 'static,
    B: sc_client_api::Backend<Block> + 'static,
{
    use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer};
    use sc_consensus_babe_rpc::{Babe, BabeApiServer};
    use sc_consensus_grandpa_rpc::{Grandpa, GrandpaApiServer};
    use sc_consensus_manual_seal::rpc::{ManualSeal, ManualSealApiServer};
    use substrate_frame_rpc_system::{System, SystemApiServer};
    let mut module = RpcModule::new(());
    let FullDeps {
        client,
        pool,
        select_chain,
        command_sink_opt,
        babe,
        grandpa,
    } = deps;
    if let Some(babe) = babe {
        let BabeDeps {
            babe_worker_handle,
            keystore,
        } = babe;
        module.merge(
            Babe::new(client.clone(), babe_worker_handle, keystore, select_chain).into_rpc(),
        )?;
    }
    let GrandpaDeps {
        shared_voter_state,
        shared_authority_set,
        justification_stream,
        subscription_executor,
        finality_provider,
    } = grandpa;
    module.merge(
        Grandpa::new(
            subscription_executor,
            shared_authority_set,
            shared_voter_state,
            justification_stream,
            finality_provider,
        )
        .into_rpc(),
    )?;
    module.merge(System::new(client.clone(), pool).into_rpc())?;
    module.merge(TransactionPayment::new(client).into_rpc())?;
    if let Some(command_sink) = command_sink_opt {
        module.merge(ManualSeal::new(command_sink).into_rpc())?;
    };
    Ok(module)
}