#!/usr/bin/env python3
"""Fetch information about coins and tokens supported by SafeWISE and update it in coins_details.json."""
import time
import json
import requests
import pprint
import ethereum_tokens_gen

COINS = {}

def coinmarketcap_init():
    global COINS

    try:
        COINS = json.load(open('coinmarketcap.json', 'r'))
    except FileNotFoundError:
        pass
    else:
        if COINS["1"]["last_updated"] > time.time() - 3600:
            print("Using local cache of coinmarketcap")
            return

    print("Updating coins from coinmarketcap")
    total = None
    COINS = {}

    while total is None or len(COINS) < total:
        url = 'https://api.coinmarketcap.com/v2/ticker/?start=%d&convert=USD&limit=100' % (len(COINS)+1)
        data = requests.get(url).json()
        COINS.update(data['data'])
        if total is None:
            total = data['metadata']['num_cryptocurrencies']

        print("Fetched %d of %d coins" % (len(COINS), total))
        time.sleep(1)

    json.dump(COINS, open('coinmarketcap.json', 'w'), sort_keys=True, indent=4)


def coinmarketcap_info(shortcut):
    global COINS
    shortcut = shortcut.replace(' ', '-').lower()

    for _id in COINS:
        coin = COINS[_id]
        #print(shortcut, coin['website_slug'])
        if shortcut == coin['website_slug']:
            #print(coin)
            return coin

def update_marketcap(obj, shortcut):
    try:
        obj['marketcap_usd'] = int(float(coinmarketcap_info(shortcut)['quotes']['USD']['market_cap']))
    except:
        pass
        # print("Marketcap info not found for", shortcut)

def coinmarketcap_global():
    url = 'https://api.coinmarketcap.com/v2/global'
    ret = requests.get(url)
    data = ret.json()
    return data

def set_default(obj, key, default_value):
    obj[key] = obj.setdefault(key, default_value)

def update_info(details):
    details['info']['updated_at'] = int(time.time())
    details['info']['updated_at_readable'] = time.asctime()

    details['info']['t1_coins'] = len([True for _, c in details['coins'].items() if c['t1_enabled'] == 'yes' and not c.get('hidden', False)])
    details['info']['t2_coins'] = len([True for _, c in details['coins'].items() if c['t2_enabled'] == 'yes' and not c.get('hidden', False)])

    try:
        details['info']['total_marketcap_usd'] = int(coinmarketcap_global()['data']['quotes']['USD']['total_market_cap'])
    except:
        pass

    marketcap = 0
    for k, c in details['coins'].items():
        if c['t1_enabled'] == 'yes' or c['t2_enabled'] == 'yes':
            marketcap += details['coins'][k].setdefault('marketcap_usd', 0)
    details['info']['marketcap_usd'] = marketcap

def check_unsupported(details, prefix, supported):
    for k in details['coins'].keys():
        if not k.startswith(prefix):
            continue
        if k not in supported:
            print("%s not supported by SafeWISE? (Possible manual entry)" % k)

def update_coins(details):
    coins = json.load(open('coins.json', 'r'))

    supported = []
    for coin in coins:
        if coin['firmware'] != 'stable':
            continue

        # print("Updating", coin['coin_label'], coin['coin_shortcut'])
        key = "coin:%s" % coin['coin_shortcut']
        supported.append(key)
        out = details['coins'].setdefault(key, {})
        out['type'] = 'coin'
        set_default(out, 'shortcut', coin['coin_shortcut'])
        set_default(out, 'name', coin['coin_label'])
        set_default(out, 'links', {})
        set_default(out, 't1_enabled', 'yes')
        set_default(out, 't2_enabled', 'yes')
        update_marketcap(out, coin.get('coinmarketcap_alias', coin['coin_label']))

    check_unsupported(details, 'coin:', supported)

def update_erc20(details):
    networks = ['eth',
        'exp',
        # 'rop',
        # 'rin',
        'ubq',
        # 'rsk',
        # 'kov',
        'etc',
    ]

    LATEST_T1 = 'https://raw.githubusercontent.com/trezor/trezor-mcu/v1.6.1/firmware/ethereum_tokens.c'
    LATEST_T2 = 'https://raw.githubusercontent.com/trezor/trezor-core/v2.0.6/src/apps/ethereum/tokens.py'

    tokens = ethereum_tokens_gen.get_tokens()
    tokens_t1 = requests.get(LATEST_T1).text
    tokens_t2 = requests.get(LATEST_T2).text

    supported = []
    for t in tokens:
        # print('Updating', t['symbol'])

        if t['chain'] not in networks:
            print('Skipping, %s is disabled' % t['chain'])
            continue

        key = "erc20:%s:%s" % (t['chain'], t['symbol'])
        supported.append(key)
        out = details['coins'].setdefault(key, {})
        out['type'] = 'erc20'
        out['network'] = t['chain']
        out['address'] = t['address']

        set_default(out, 'shortcut', t['symbol'])
        set_default(out, 'name', t['name'])
        set_default(out, 'links', {})

        if "\" %s\"" % t['symbol'] in tokens_t1:
            out['t1_enabled'] = 'yes'
        else:
            out['t1_enabled'] = 'soon'

        if "'%s'" % t['symbol'] in tokens_t2:
            out['t2_enabled'] = 'yes'
        else:
            out['t2_enabled'] = 'soon'

        out['links']['MyCrypto Wallet'] = 'https://mycrypto.com'
        out['links']['MyEtherWallet'] = 'https://www.myetherwallet.com'

        if t['website']:
            out['links']['Homepage'] = t['website']
        if t.get('social', {}).get('github', None):
            out['links']['Github'] = t['social']['github']

        update_marketcap(out, out.get('coinmarketcap_alias', t['symbol']))

    check_unsupported(details, 'erc20:', supported)

def update_ethereum(details):
    out = details['coins'].setdefault('coin2:ETH', {})
    out['type'] = 'coin'
    set_default(out, 'shortcut', 'ETH')
    set_default(out, 'name', 'Ethereum')
    set_default(out, 't1_enabled', 'yes')
    set_default(out, 't2_enabled', 'yes')
    update_marketcap(out, 'ethereum')

    out = details['coins'].setdefault('coin2:ETC', {})
    out['type'] = 'coin'
    set_default(out, 'shortcut', 'ETC')
    set_default(out, 'name', 'Ethereum Classic')
    set_default(out, 't1_enabled', 'yes')
    set_default(out, 't2_enabled', 'yes')
    update_marketcap(out, 'ethereum-classic')

    out = details['coins'].setdefault('coin2:RSK', {})
    out['type'] = 'coin'
    set_default(out, 'shortcut', 'RSK')
    set_default(out, 'name', 'Rootstock')
    set_default(out, 't1_enabled', 'yes')
    set_default(out, 't2_enabled', 'yes')
    update_marketcap(out, 'rootstock')

    out = details['coins'].setdefault('coin2:EXP', {})
    out['type'] = 'coin'
    set_default(out, 'shortcut', 'EXP')
    set_default(out, 'name', 'Expanse')
    set_default(out, 't1_enabled', 'yes')
    set_default(out, 't2_enabled', 'yes')
    update_marketcap(out, 'expanse')

    out = details['coins'].setdefault('coin2:UBQ', {})
    out['type'] = 'coin'
    set_default(out, 'shortcut', 'UBQ')
    set_default(out, 'name', 'Ubiq')
    set_default(out, 't1_enabled', 'yes')
    set_default(out, 't2_enabled', 'yes')
    update_marketcap(out, 'ubiq')

    out = details['coins'].setdefault('coin2:ELLA', {})
    out['type'] = 'coin'
    set_default(out, 'shortcut', 'ELLA')
    set_default(out, 'name', 'Ellaism')
    set_default(out, 't1_enabled', 'yes')
    set_default(out, 't2_enabled', 'yes')
    update_marketcap(out, 'ellaism')

    out = details['coins'].setdefault('coin2:EGEM', {})
    out['type'] = 'coin'
    set_default(out, 'shortcut', 'EGEM')
    set_default(out, 'name', 'EtherGem')
    set_default(out, 't1_enabled', 'yes')
    set_default(out, 't2_enabled', 'yes')
    update_marketcap(out, 'egem')

    out = details['coins'].setdefault('coin2:ETSC', {})
    out['type'] = 'coin'
    set_default(out, 'shortcut', 'ETSC')
    set_default(out, 'name', 'EthereumSocial')
    set_default(out, 't1_enabled', 'yes')
    set_default(out, 't2_enabled', 'yes')
    update_marketcap(out, 'etsc')

    ut = details['coins'].setdefault('coin2:EOSC', {})
    out['type'] = 'coin'
    set_default(out, 'shortcut', 'EOSC')
    set_default(out, 'name', 'EOS Classic')
    set_default(out, 't1_enabled', 'yes')
    set_default(out, 't2_enabled', 'yes')
    update_marketcap(out, 'eosc')

def update_mosaics(details):
    d = json.load(open('defs/nem/nem_mosaics.json'))
    supported = []
    for mosaic in d:
        # print('Updating', mosaic['name'], mosaic['ticker'])

        key = "mosaic:%s" % mosaic['ticker'].strip()
        supported.append(key)
        out = details['coins'].setdefault(key, {})
        out['type'] = 'mosaic'
        set_default(out, 'shortcut', mosaic['ticker'].strip())
        set_default(out, 'name', mosaic['name'])
        set_default(out, 't1_enabled', 'yes')
        set_default(out, 't2_enabled', 'yes')

        update_marketcap(out, out.get('coinmarketcap_alias', out['name']))

    check_unsupported(details, 'mosaic:', supported)

def check_missing_details(details):
    for k in details['coins'].keys():
        coin = details['coins'][k]
        hide = False

        if 'links' not in coin:
            print("%s: Missing links" % k)
            hide = True
        if 'Homepage' not in coin['links']:
            print("%s: Missing homepage" % k)
            hide = True
        if coin['t1_enabled'] not in ('yes', 'no', 'planned', 'soon'):
            print("%s: Unknown t1_enabled" % k)
            hide = True
        if coin['t2_enabled'] not in ('yes', 'no', 'planned', 'soon'):
            print("%s: Unknown t2_enabled" % k)
            hide = True
        if 'SafeWISE Wallet' in coin['links'] and coin['links']['SafeWISE Wallet'] != 'https://wallet.safewise.io':
            print("%s: Strange URL for SafeWISE Wallet" % k)
            hide = True

        for w in [ x.lower() for x in coin['links'].keys() ]:
            if 'wallet' in w or 'electrum' in w:
                break
        else:
            if coin['t1_enabled'] == 'yes' or coin['t2_enabled'] == 'yes':
                print("%s: Missing wallet" % k)
                hide = True
            else:
                print("%s: Missing wallet, but not hiding" % k)

        if hide:
            # If any of important detail is missing, hide coin from list
            coin['hidden'] = 1

        if not hide and coin.get('hidden'):
            print("%s: Details are OK, but coin is still hidden" % k)

    for k in details['coins'].keys():
        if details['coins'][k].get('hidden') == 1:
            print("%s: Coin is hidden" % k)

if __name__ == '__main__':
    try:
        details = json.load(open('coins_details.json', 'r'))
    except FileNotFoundError:
        details = {'coins': {}, 'info': {}}

    coinmarketcap_init()
    update_coins(details)
    update_erc20(details)
    update_ethereum(details)
    update_mosaics(details)
    update_info(details)
    check_missing_details(details)

    print(json.dumps(details['info'], sort_keys=True, indent=4))
    json.dump(details, open('coins_details.json', 'w'), sort_keys=True, indent=4)
