from tinyman.v1.client import TinymanTestnetClient
from algosdk import account, encoding , mnemonic
from bootstrap import prepare_bootstrap_transactions
from algosdk.v2client import algod

from tinyman.v1.pools import Pool
from tinyman.assets import Asset
from tinyman.utils import wait_for_confirmation
from algosdk.v2client.algod import AlgodClient
from tinyman.v1.client import TinymanClient

from algosdk.v2client.algod import AlgodClient
from client import TinymanClient

import sys
import re

    

def swap(client,action,aID1,aID2,account,mne,amount):
    if(not client.is_opted_in(account['address'])):
        print('Account not opted into app, opting in now..')
        transaction_group = client.prepare_app_optin_transactions(account['address'])
        for i, txn in enumerate(transaction_group.transactions):
            if txn.sender == account['address']:
                transaction_group.signed_transactions[i] = txn.sign(account['private_key'])
        txid = client.algod.send_transactions(transaction_group.signed_transactions)
        wait_for_confirmation(txid)
    # Fetch our two assets of interest
    ASA = client.fetch_asset(aID1)
    BTC = client.fetch_asset(aID2)
    
    # Create the pool we will work with and fetch its on-chain state
    #pool = Pool(client, asset_a=ASA, asset_b=BTC, fetch=True)
    pool = client.fetch_pool(ASA, BTC)
    r = pool.info()
    if(not client.asset_is_opted_in(aID1)):
        print('Account not opted into asset {aID1}, opting in now..')
        transaction_group = client.prepare_asset_optin_transactions(aID1, account['address'])
        for i, txn in enumerate(transaction_group.transactions):
            if txn.sender == account['address']:
                transaction_group.signed_transactions[i] = txn.sign(account['private_key'])
        txid = client.algod.send_transactions(transaction_group.signed_transactions)
        #wait_for_confirmation(txid)
    if(not client.asset_is_opted_in(aID2) and aID2 > 0):
        print('Account not opted into asset {aID2}, opting in now..')
        transaction_group = client.prepare_asset_optin_transactions(aID2, account['address'])
        for i, txn in enumerate(transaction_group.transactions):
            if txn.sender == account['address']:
                transaction_group.signed_transactions[i] = txn.sign(account['private_key'])
        txid = client.algod.send_transactions(transaction_group.signed_transactions)
        #wait_for_confirmation(txid)
    #amount = 10_000_000
    
    # Get a quote for a swap of 1 ALGO to TINYUSDC with 1% slippage tolerance
    if action == 'add':
        quote = pool.fetch_fixed_input_swap_quote(BTC(amount), slippage=0.01)
        
    elif action == 'remove':
        quote = pool.fetch_fixed_input_swap_quote(ASA(amount), slippage=0.01)
    
    #
    print(quote)
    print(f'ASA per BTC satoshi: {str(quote.price)}')
    print(f'ASA per BTC satoshi (worst case): {str(quote.price_with_slippage)}')
    
    # We only want to sell if BTC is > 0 ASA
    if quote.price_with_slippage > 0:
        print(f'Swapping {quote.amount_in} to {quote.amount_out_with_slippage}')
        # Prepare a transaction group
        transaction_group = pool.prepare_swap_transactions(
            amount_in=quote.amount_in,
            amount_out=quote.amount_out_with_slippage,
            swap_type='fixed-input',
            swapper_address=account['address'],
        )
        # Sign the group with our key
        for i, txn in enumerate(transaction_group.transactions):
            if txn.sender == account['address']:
                transaction_group.signed_transactions[i] = txn.sign(account['private_key'])
        txid = client.algod.send_transactions(transaction_group.signed_transactions)
        wait_for_confirmation(client.algod, txid)
    
        # Check if any excess remaining after the swap
        excess = pool.fetch_excess_amounts(account['address'])
        if ASA.id in excess:
            amount = excess[ASA.id]
            print(f'Excess: {amount}')
            # We might just let the excess accumulate rather than redeeming if its < 1 ASA
            if amount > 0:
                transaction_group = pool.prepare_redeem_transactions(amount, account['address'])
                # Sign the group with our key
                for i, txn in enumerate(transaction_group.transactions):
                    if txn.sender == account['address']:
                        transaction_group.signed_transactions[i] = txn.sign(account['private_key'])
                txid = client.algod.send_transactions(transaction_group.signed_transactions)
                wait_for_confirmation(client.algod, txid)




action = sys.argv[1]
#


if action == "bootstrap":
    pooler_address = sys.argv[4]
    aID1 = int(sys.argv[2])
    aID2 =  int(sys.argv[3])
    mne = sys.argv[5]
    priv_key = mnemonic.to_private_key(mne)
    account = {
        'address': pooler_address,
        'private_key': priv_key,
    }
    client = TinymanTestnetClient(user_address=account['address'])
    if(not client.is_opted_in(account['address'])):
        print('Account not opted into app, opting in now..')
        transaction_group = client.prepare_app_optin_transactions(account['address'])
        for i, txn in enumerate(transaction_group.transactions):
            if txn.sender == account['address']:
                transaction_group.signed_transactions[i] = txn.sign(account['private_key'])
        txid = client.algod.send_transactions(transaction_group.signed_transactions)
        #wait_for_confirmation(txid)
        
    if(not client.asset_is_opted_in(aID1, account['address'])):
        print('Account not opted into asset {aID1}, opting in now..')
        transaction_group = client.prepare_asset_optin_transactions(aID1, account['address'])
        for i, txn in enumerate(transaction_group.transactions):
            if txn.sender == account['address']:
                transaction_group.signed_transactions[i] = txn.sign(account['private_key'])
        txid = client.algod.send_transactions(transaction_group.signed_transactions)
        #wait_for_confirmation(txid)
    '''    
    if(not client.asset_is_opted_in(aID2)):
        print('Account not opted into asset {aID2}, opting in now..')
        transaction_group = client.prepare_asset_optin_transactions(aID1, account['address'])
        for i, txn in enumerate(transaction_group.transactions):
            if txn.sender == account['address']:
                transaction_group.signed_transactions[i] = txn.sign(account['private_key'])
        txid = client.algod.send_transactions(transaction_group.signed_transactions)
        #wait_for_confirmation(txid)
    '''
    # Fetch our two assets of interest
    TINYUSDC = client.fetch_asset(aID1)
    ALGO = client.fetch_asset(aID2)
    
    
    # Fetch the pool we will work with
    pool = client.fetch_pool(TINYUSDC, ALGO)
    transaction_group = pool.prepare_bootstrap_transactions(pooler_address=account['address'])
    transaction_group.sign_with_private_key(account['address'], account['private_key'])
    result = client.submit(transaction_group, wait=True)
    
    pool = client.fetch_pool(TINYUSDC, ALGO)
    pool.refresh()
    r = pool.info()
    '''
    if(not client.asset_is_opted_in(r['liquidity_asset_id'], account['address'])):
        print(f"Account not opted into asset {r['liquidity_asset_id']}, opting in now..")
        transaction_group = client.prepare_asset_optin_transactions(r['liquidity_asset_id'], account['address'])
        transaction_group.sign_with_private_key(account['address'], account['private_key'])
        client.submit(transaction_group, wait=True)
        #wait_for_confirmation(txid)
    '''
    print(r)


if action == "accState":
    pooler_address = sys.argv[2]
    Pool.prep_acc_state(AlgodTestnetClient, pooler_address)
if action == "swap":
    pooler_address = sys.argv[5]
    mne = sys.argv[6]
    action = sys.argv[7]
    aID1 = int(sys.argv[2])
    aID2 =  int(sys.argv[3])
    amount =  int(sys.argv[4])
    
    priv_key = mnemonic.to_private_key(mne)
    account = {
        'address': pooler_address,
        'private_key': priv_key,
    }
    
    client = TinymanTestnetClient(user_address=account['address'])
    
    swap(client,action,aID1,aID2,account,mne,amount)
    
    
    
if action == "quote":
    
    
    client = TinymanTestnetClient()
    
    aID1 = int(sys.argv[2])
    aID2 =  int(sys.argv[3])
    pooler_address = sys.argv[4]

    # Fetch our two assets of interest
    ASA = client.fetch_asset(aID1)
    BTC = client.fetch_asset(aID2)
    
    # Fetch the pool we will work with
    pool = client.fetch_pool(ASA, BTC)
    
    r = pool.info()

    # Get a quote for a swap of 1 ASA with 1% slippage tolerance
    quote = pool.fetch_fixed_input_swap_quote(ASA(1000000), slippage=0.01)
    reg = re.search("('([^/,]*)')",str(quote.amount_out))
    result = reg.group(1)

    #print(r)
    print(result)
    account_info = client.algod.account_info(pooler_address)
    amount = 0
    assets = {a['asset-id']: a for a in account_info['assets']}
    print(assets[aID1]['amount'])
    #for i, ast in enumerate(assets):
        #print(ast)
        #if int(ast) == aID1:
            #amount = ast['amount']
            
    #print(amount)
    
if action == "pooling":
    pooler_address = sys.argv[4]
    mne = sys.argv[5]
    aID1 = int(sys.argv[2])
    aID2 =  int(sys.argv[3])
    
    priv_key = mnemonic.to_private_key(mne)
    account = {
        'address': pooler_address,
        'private_key': priv_key,
    }

    client = TinymanTestnetClient(user_address=account['address'])
    # By default all subsequent operations are on behalf of user_address
    if(not client.is_opted_in(account['address'])):
        print('Account not opted into app, opting in now..')
        transaction_group = client.prepare_app_optin_transactions(account['address'])
        for i, txn in enumerate(transaction_group.transactions):
            if txn.sender == account['address']:
                transaction_group.signed_transactions[i] = txn.sign(account['private_key'])
        txid = client.algod.send_transactions(transaction_group.signed_transactions)
        result = client.submit(transaction_group, wait=True)
        #wait_for_confirmation(txid)
        
    # Fetch our two assets of interest
    ASA = client.fetch_asset(aID1)
    BTC = client.fetch_asset(aID2)
    
    # Create the pool we will work with and fetch its on-chain state
    #pool = Pool(client, asset_a=ASA, asset_b=BTC, fetch=True)
    # Fetch the pool we will work with
    pool = client.fetch_pool(ASA, BTC)
    
    info = pool.fetch_pool_position()
    share = float(info['share']) * 100
    
    print(info[pool.liquidity_asset])
    print(float(share))
    #print(f'Pool Tokens: {info[pool.liquidity_asset]}')
    #print(f'Assets: {info[ASA]}, {info[BTC]}')
    #print(f'Share of pool: {share:.3f}%')

