from starkware.starknet.public.abi import get_selector_from_name
from starkware.starknet.definitions.general_config import StarknetChainId
from starkware.starknet.core.os.transaction_hash.transaction_hash import calculate_transaction_hash_common, TransactionHashPrefix
import logging

LOGGER = logging.getLogger(__name__)

TRANSACTION_VERSION = 0

class TransactionSender():
  def __init__(self, account):
    self.account = account

  async def send_transaction(self, calls, signer, nonce=None, max_fee=0):
    if nonce is None:
      execution_info = await self.account.get_nonce().call()
      nonce = execution_info.result.nonce

    calls_with_selector = [(call[0], get_selector_from_name(call[1]), call[2]) for call in calls]
    call_array, calldata = from_call_to_call_array(calls)

    transaction_hash = get_transaction_hash(self.account.contract_address, call_array, calldata, nonce, max_fee)

    signature = list(signer.sign(transaction_hash))

    return await self.account.__execute__(call_array, calldata, nonce).invoke(signature=signature)

def from_call_to_call_array(calls):
  call_array = []
  calldata = []
  for call in calls:
    assert len(call) == 3, "Invalid call parameters"
    entry = (call[0], get_selector_from_name(call[1]), len(calldata), len(call[2]))
    call_array.append(entry)
    calldata.extend(call[2])
  return call_array, calldata

def get_transaction_hash(account, call_array, calldata, nonce, max_fee):
  execute_calldata = [
    len(call_array),
    *[x for t in call_array for x in t],
    len(calldata),
    *calldata,
    nonce]

  return calculate_transaction_hash_common(
    TransactionHashPrefix.INVOKE,
    TRANSACTION_VERSION,
    account,
    get_selector_from_name('__execute__'),
    execute_calldata,
    max_fee,
    StarknetChainId.TESTNET.value,
    []
  )
