import {useStore} from "@/store/store.js";
import {metadataMap} from "@/version.js";
import {newContract} from "@/blockchain/contract.js";
import {provider} from "@/blockchain/provider.js";
import {socket} from "@/socket.js";


// synchronous version may return null but will trigger a lookup
export function token(chainId, addr) {
    const chainMd = metadataMap[chainId];
    if (chainMd===undefined) {
        console.warn('no metadata for chain', chainId)
        return null
    }
    const found = chainMd[addr]
    return found ? found : null
}


// async version doesnt return until it has a token value
export async function getToken(chainId, addr) {
    const s = useStore()
    if (addr===undefined) { // todo remove check
        console.warn('getToken(addr) is deprecated.  use getToken(chainId,addr)')
        addr = chainId
        chainId = s.chainId
    }
    let found = metadataMap[chainId][addr]
    // console.log('token from metadataMap', found)
    if (found)
        return found
    if (!(addr in s.tokens))
        await addExtraToken(chainId, addr)
    let result = s.tokens[addr]
    if (!result) {
        result = {
            n: addr,
            a: addr,
            s: addr,
            d: 0,
        }
    }
    return result
}


const _inFlightLookups = {}

export async function addExtraToken(chainId, addr) {
    // console.log('addExtraToken', chainId, addr)
    if (addr===undefined) { // todo remove check
        console.warn('addExtraToken(addr) is deprecated.  use addExtraToken(chainId,addr)')
        addr = chainId
        chainId = s.chainId
    }
    if( !addr ) {
        console.log('ignoring call to add extra token', addr)
        return
    }
    if( !_inFlightLookups[addr] ) {
        _inFlightLookups[addr] = true
        const prom = new Promise((resolve) => {
            const s = useStore()
            console.log('querying token', addr)
            socket.emit('lookupToken', chainId, addr, async (info) => {
                console.log('server token info', addr, info)
                if (info !== null) {
                    s.addToken(chainId, info)
                    resolve(info)
                }
                else {
                    if( provider===null ) {
                        console.warn('warning: token lookup cancelled due to null provider', addr)
                        resolve(null)
                    }
                    else {
                        for( let tries=1; tries<=5; tries++ ) {
                            try {
                                const token = await newContract(addr, 'IERC20Metadata', provider)
                                const [name, symbol, decimals] = await Promise.all([token.name(), token.symbol(), token.decimals()])
                                info = {
                                    a: addr,
                                    n: name,
                                    s: symbol,
                                    d: decimals,
                                }
                                s.addToken(chainId, info)
                                resolve(info)
                                break
                            }
                            catch (e) {
                                console.warn(`Could not lookup token ${addr}`, e)
                            }
                        }
                    }
                }
            })
        })
        const result = await prom
        delete _inFlightLookups[addr]
        return result
    }
}
