use crate::impl_nexa_hashencode;
use anyhow::Result;
use bitcoin_hashes::{sha256, Hash};

use bitcoincash::Network;
use bitcoincash::Script;

#[cfg(nexa)]
pub type BlockHeader = crate::nexa::block::BlockHeader;
#[cfg(bch)]
pub type BlockHeader = bitcoincash::blockdata::block::BlockHeader;

#[cfg(nexa)]
pub type BlockHash = crate::nexa::hash_types::BlockHash;
#[cfg(bch)]
pub type BlockHash = bitcoincash::hash_types::BlockHash;

#[cfg(nexa)]
pub type Block = crate::nexa::block::Block;
#[cfg(bch)]
pub type Block = bitcoincash::blockdata::block::Block;

#[cfg(nexa)]
pub type OutPoint = crate::nexa::transaction::OutPoint;
#[cfg(bch)]
pub type OutPoint = bitcoincash::blockdata::transaction::OutPoint;

#[cfg(nexa)]
pub type TxIn = crate::nexa::transaction::TxIn;
#[cfg(bch)]
pub type TxIn = bitcoincash::blockdata::transaction::TxIn;

#[cfg(nexa)]
pub type TxOut = crate::nexa::transaction::TxOut;
#[cfg(bch)]
pub type TxOut = bitcoincash::blockdata::transaction::TxOut;

#[cfg(nexa)]
pub type Transaction = crate::nexa::transaction::Transaction;
#[cfg(bch)]
pub type Transaction = bitcoincash::blockdata::transaction::Transaction;

#[cfg(nexa)]
pub type TokenID = crate::nexa::token::TokenID;
#[cfg(bch)]
pub type TokenID = bitcoincash::hash_types::TokenID;

hash_newtype!(
    OutPointHash,
    sha256::Hash,
    32,
    doc = "Hash pointing to a outpoint (utxo). The hash of txid & output index.",
    true
);
impl_nexa_hashencode!(OutPointHash);

hash_newtype!(
    ScriptHash,
    sha256::Hash,
    32,
    doc = "Hash of a Bitcoin Script",
    true
);

impl_nexa_hashencode!(ScriptHash);

impl ScriptHash {
    pub fn from_script(s: &Script) -> ScriptHash {
        ScriptHash::hash(&s[..])
    }

    /**
     * ScriptHash where any token amounts are replaced with OP_0.
     */
    #[cfg(nexa)]
    pub fn normalized_from_txout(o: &TxOut) -> ScriptHash {
        match o.scriptpubkey_without_token() {
            Ok(Some(new_script)) => Self::from_script(&new_script),
            _ => Self::from_script(&o.script_pubkey),
        }
    }

    #[cfg(bch)]
    pub fn normalized_from_txout(o: &TxOut) -> ScriptHash {
        Self::from_script(&o.script_pubkey)
    }
}

#[cfg(bch)]
pub(crate) fn regtest_genesis_block() -> Block {
    bitcoincash::blockdata::constants::genesis_block(bitcoincash::Network::Regtest)
}

#[cfg(nexa)]
pub fn regtest_genesis_block() -> Block {
    todo!()
}

#[cfg(bch)]
pub fn net_magic(net: Network) -> u32 {
    net.net_magic()
}

#[cfg(nexa)]
pub fn net_magic(net: Network) -> u32 {
    match net {
        Network::Bitcoin => 0x21122772,
        Network::Testnet => 0x22122772,
        Network::Regtest => 0xEAEFE5EA,
        _ => panic!("Unknown network"),
    }
}

#[cfg(bch)]
pub type NetworkMessage = bitcoincash::network::message::NetworkMessage;
#[cfg(nexa)]
pub type NetworkMessage = crate::nexa::message::NetworkMessage;

#[cfg(bch)]
pub type RawNetworkMessage = bitcoincash::network::message::RawNetworkMessage;
#[cfg(nexa)]
pub type RawNetworkMessage = crate::nexa::message::RawNetworkMessage;
