use frame_support::{pallet_prelude::*, storage::PrefixIterator};
use sp_std::vec::Vec;
use sp_runtime::{
    offchain::http::PendingRequest,
    traits::{AtLeast32BitUnsigned, Member},
    DispatchResult,
};

pub trait NetworkDataBasicHandler {
     type NetworkCurve: Parameter
        + Member
        + Default
        + Copy
        + TypeInfo
        + MaybeSerializeDeserialize
        + MaxEncodedLen;
     type NetworkType: Parameter
        + Member
        + Default
        + Copy
        + TypeInfo
        + MaybeSerializeDeserialize
        + MaxEncodedLen;
    type NetworkId: Parameter
        + Member
        + AtLeast32BitUnsigned
        + Default
        + Copy
        + TypeInfo
        + MaybeSerializeDeserialize
        + MaxEncodedLen;
}

pub trait NetworkDataInspectHandler<Network>: NetworkDataBasicHandler {
    fn count() -> u32;
    fn contains_key(n: &Self::NetworkId) -> bool;
    fn curve_exists(c: &Self::NetworkCurve) -> bool;
    fn network_for_block(b: impl Into<usize>) -> Option<(Self::NetworkId, Network)>;
    fn get(n: &Self::NetworkId) -> Option<Network>;
    fn iter() -> PrefixIterator<(Self::NetworkId, Network)>;
    fn iter_indexes() -> impl Iterator<Item = Self::NetworkId>;
    fn iter_curves() -> impl Iterator<Item = Self::NetworkCurve>;
    fn iter_types_by_curve(n: &Self::NetworkCurve) -> impl Iterator<Item = Self::NetworkType>;
}

pub trait NetworkDataMutateHandler<Network, Balance>: NetworkDataInspectHandler<Network> {
    fn register(chain_id: Self::NetworkId, network: Network) -> DispatchResult;
    fn remove(chain_id: Self::NetworkId) -> DispatchResult;

    fn register_incoming(chain_id: &Self::NetworkId, amount: Balance) -> Result<Balance, ()>;
    fn register_outgoing(chain_id: &Self::NetworkId, amount: Balance) -> Result<Balance, ()>;
}

pub trait NetworkRpcResolver<W, B, H, I, S> {
    fn get_block_request_body(&self, id: I) -> Vec<u8>;
    fn get_hash_request_body(
        &self,
        id: I,
        block: B,
        session: S,
        contract_ref: &[u8],
        selector_ref: &[u8],
    ) -> Vec<u8>;
    fn parse_block_requests(
        &self,
        pending_requests: Vec<PendingRequest>,
        deadline: sp_runtime::offchain::Timestamp,
        request_id: I,
    ) -> Vec<B>;
    fn parse_hash_requests(
        &self,
        pending_requests: Vec<PendingRequest>,
        deadline: sp_runtime::offchain::Timestamp,
        request_id: I,
    ) -> Vec<(H, S)>;
}
