# import libraries
import subprocess
import json
import os
from constants import *
from dotenv import load_dotenv
from web3 import Web3
from eth_account import Account
from bit import PrivateKeyTestnet
from bit.network import NetworkAPI
from web3.middleware import geth_poa_middleware
from web3.gas_strategies.time_based import medium_gas_price_strategy

load_dotenv()

w3 = Web3(Web3.HTTPProvider("http://127.0.0.1:8545"))

w3.middleware_onion.inject(geth_poa_middleware, layer=0)
w3.eth.setGasPriceStrategy(medium_gas_price_strategy)

mnemonic = os.getenv('MNEMONIC')

# Function to create and store keys/addresses.
def derive_wallets(coin):
    command = f'php hd-wallet-derive/hd-wallet-derive.php -g --mnemonic="{mnemonic}" --cols=path,address,privkey,pubkey --format=json --coin="{coin}" --numderive=2'
    p = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
    output, err = p.communicate()
    p_status = p.wait()
    keys = json.loads(output)
    print(keys)
    return keys

# Dictionary which captures the generated keys and hashes from the derive function.
coins = {
    ETH: derive_wallets(ETH),
    BTCTEST: derive_wallets(BTCTEST)
}


# This function takes the wallet accounts generated by the hd-wallet-derive tool and turns them into interactive account objects.
def priv_key_to_account(coin, priv_key):
    if coin == ETH:
        return Account.privateKeyToAccount(priv_key)
    if coin == BTCTEST:
        return PrivateKeyTestnet(priv_key)


# This function takes in the parameters needed to create a full transaction that can be passed through the coin's respective networks.
# It does not need to be called by itself since it is included within the send_tx function.
def create_tx(coin, account, to, amount):
    if coin == ETH:
        gasEstimate = w3.eth.estimateGas(
            {"from": account.address, "to": to, "value": amount}
        )
        return {
            "from": account.address,
            "to": to,
            "value": amount,
            "gasPrice": w3.eth.gasPrice,
            "gas": gasEstimate,
            "nonce": w3.eth.getTransactionCount(account.address),
#             "chainID": Web3.eth.chainId
        }
    if coin == BTCTEST:
        return PrivateKeyTestnet.prepare_transaction(account.address, [(to, amount, BTC)])

# This function will be used to execute the movement of the currencies by broadcasting the completed transaction statements to the respective network.

def send_tx(coin, account, to, amount):
    raw_tx = create_tx(coin, account, to, amount)
    signed_tx = account.sign_transaction(raw_tx)
    
    if coin == ETH:
        return w3.eth.sendRawTransaction(signed_tx.rawTransaction)
    if coin == BTCTEST:
        return NetworkAPI.broadcast_tx_testnet(signed_tx)




# Initialize Ethereum Account object and transactions.
eth_account = priv_key_to_account(ETH, coins[ETH][0]['privkey'])

# The amounts appear to be extremely large because they are denominated in gwei, the small division unit of Ethereum
create_tx(ETH, eth_account, "0x7d408D1c14BAf2894aF7119A20f6F9014543F992", 5000000000000000000000)

send_tx(ETH, eth_account, "0x7d408D1c14BAf2894aF7119A20f6F9014543F992", 5000000000000000000000)



# Initialize BTC Account object and transactions.
btc_account = priv_key_to_account(BTCTEST, coins[BTCTEST][0]['privkey'])

create_tx(BTCTEST, btc_account,"mkHS9ne12qx9pS9VojpwU5xtRd4T7X7ZUt", 0.0001)

send_tx(BTCTEST, btc_account,"mkHS9ne12qx9pS9VojpwU5xtRd4T7X7ZUt", 0.0001)

