use super::{ChainState, IndexResponse};
use crate::{contract::interface_traits::Uploadable, error::CwEnvError};
use cosmwasm_std::{Addr, BlockInfo, Coin};
use serde::{de::DeserializeOwned, Serialize};
use std::fmt::Debug;
pub trait CwEnv: TxHandler + Clone {}
impl<T: TxHandler + Clone> CwEnv for T {}
pub type TxResponse<Chain> = <Chain as TxHandler>::Response;
pub trait TxHandler: ChainState + Clone {
    type Response: IndexResponse + Debug + Send + Clone;
    type Error: Into<CwEnvError> + Debug;
    type ContractSource;
    type Sender: Clone;
    fn sender(&self) -> Addr;
    fn set_sender(&mut self, sender: Self::Sender);
    fn wait_blocks(&self, amount: u64) -> Result<(), Self::Error>;
    fn wait_seconds(&self, secs: u64) -> Result<(), Self::Error>;
    fn next_block(&self) -> Result<(), Self::Error>;
    fn block_info(&self) -> Result<BlockInfo, Self::Error>;
    fn upload(&self, contract_source: &impl Uploadable) -> Result<Self::Response, Self::Error>;
    fn instantiate<I: Serialize + Debug>(
        &self,
        code_id: u64,
        init_msg: &I,
        label: Option<&str>,
        admin: Option<&Addr>,
        coins: &[cosmwasm_std::Coin],
    ) -> Result<Self::Response, Self::Error>;
    fn execute<E: Serialize + Debug>(
        &self,
        exec_msg: &E,
        coins: &[Coin],
        contract_address: &Addr,
    ) -> Result<Self::Response, Self::Error>;
    fn query<Q: Serialize + Debug, T: Serialize + DeserializeOwned>(
        &self,
        query_msg: &Q,
        contract_address: &Addr,
    ) -> Result<T, Self::Error>;
    fn migrate<M: Serialize + Debug>(
        &self,
        migrate_msg: &M,
        new_code_id: u64,
        contract_address: &Addr,
    ) -> Result<Self::Response, Self::Error>;
    fn call_as(&self, sender: &<Self as TxHandler>::Sender) -> Self {
        let mut chain = self.clone();
        chain.set_sender(sender.clone());
        chain
    }
}