import requests
import json
import time

from copy import deepcopy
from googlefinance import getQuotes
from lbrynet.conf import CURRENCIES
import logging

log = logging.getLogger(__name__)

BITTREX_FEE = 0.0025

SOURCE_TYPES = ['lbry_sd_hash', 'url', 'btih']
BASE_METADATA_FIELDS = ['title', 'description', 'author', 'language', 'license', 'content-type', 'sources']
OPTIONAL_METADATA_FIELDS = ['thumbnail', 'preview', 'fee', 'contact', 'pubkey']

# v0.0.1 metadata
METADATA_REVISIONS = {'0.0.1': {'required': BASE_METADATA_FIELDS, 'optional': OPTIONAL_METADATA_FIELDS}}
# v0.0.2 metadata additions
METADATA_REVISIONS['0.0.2'] = {'required': ['nsfw', 'ver'], 'optional': ['license_url']}
CURRENT_METADATA_VERSION = '0.0.2'

# v0.0.1 fee
FEE_REVISIONS = {'0.0.1': {'required': ['amount', 'address'], 'optional': []}}
CURRENT_FEE_REVISION = '0.0.1'


class LBRYFeeValidator(dict):
    def __init__(self, fee_dict):
        dict.__init__(self)
        assert len(fee_dict) == 1
        self.fee_version = None

        fee_to_load = deepcopy(fee_dict)

        for currency in fee_dict:
            self._verify_fee(currency, fee_to_load)

        self.amount = self._get_amount()
        self.address = self[self.currency_symbol]['address']

    def _get_amount(self):
        if isinstance(self[self.currency_symbol]['amount'], float):
            return self[self.currency_symbol]['amount']
        else:
            return float(self[self.currency_symbol]['amount'])

    def _verify_fee(self, currency, f):
        # str in case someone made a claim with a wierd fee
        assert currency in CURRENCIES, "Unsupported currency: %s" % str(currency)
        self.currency_symbol = currency
        self.update({currency: {}})
        for version in FEE_REVISIONS:
            self._load_revision(version, f)
            if not f:
                self.fee_version = version
                break
        assert f[self.currency_symbol] == {}, "Unknown fee keys: %s" % json.dumps(f.keys())

    def _load_revision(self, version, f):
        for k in FEE_REVISIONS[version]['required']:
            assert k in f[self.currency_symbol], "Missing required fee field: %s" % k
            self[self.currency_symbol].update({k: f[self.currency_symbol].pop(k)})
        for k in FEE_REVISIONS[version]['optional']:
            if k in f[self.currency_symbol]:
                self[self.currency_symbol].update({k: f[self.currency_symbol].pop(k)})


class LBRYFee(LBRYFeeValidator):
    def __init__(self, fee_dict, rate_dict, bittrex_fee=None):
        LBRYFeeValidator.__init__(self, fee_dict)
        self.bittrex_fee = BITTREX_FEE if bittrex_fee is None else bittrex_fee
        rates = deepcopy(rate_dict)

        assert 'BTCLBC' in rates and 'USDBTC' in rates
        for fx in rate_dict:
            assert int(time.time()) - int(rates[fx]['ts']) < 3600, "%s quote is out of date" % fx
        self._USDBTC = {'spot': rates['USDBTC']['spot'], 'ts': rates['USDBTC']['ts']}
        self._BTCLBC = {'spot': rates['BTCLBC']['spot'], 'ts': rates['BTCLBC']['ts']}

    def to_lbc(self):
        r = None
        if self.currency_symbol == "LBC":
            r = round(float(self.amount), 5)
        elif self.currency_symbol == "BTC":
            r = round(float(self._btc_to_lbc(self.amount)), 5)
        elif self.currency_symbol == "USD":
            r = round(float(self._btc_to_lbc(self._usd_to_btc(self.amount))), 5)
        assert r is not None
        return r

    def to_usd(self):
        r = None
        if self.currency_symbol == "USD":
            r = round(float(self.amount), 5)
        elif self.currency_symbol == "BTC":
            r = round(float(self._btc_to_usd(self.amount)), 5)
        elif self.currency_symbol == "LBC":
            r = round(float(self._btc_to_usd(self._lbc_to_btc(self.amount))), 5)
        assert r is not None
        return r

    def _usd_to_btc(self, usd):
        return self._USDBTC['spot'] * float(usd)

    def _btc_to_usd(self, btc):
        return float(btc) / self._USDBTC['spot']

    def _btc_to_lbc(self, btc):
        return float(btc) * self._BTCLBC['spot'] / (1.0 - self.bittrex_fee)

    def _lbc_to_btc(self, lbc):
        return self._BTCLBC['spot'] / float(lbc)


class Metadata(dict):
    def __init__(self, metadata):
        dict.__init__(self)
        self.meta_version = None
        metadata_to_load = deepcopy(metadata)

        self._verify_sources(metadata_to_load)
        self._verify_metadata(metadata_to_load)

    def _load_revision(self, version, metadata):
        for k in METADATA_REVISIONS[version]['required']:
            assert k in metadata, "Missing required metadata field: %s" % k
            self.update({k: metadata.pop(k)})
        for k in METADATA_REVISIONS[version]['optional']:
            if k == 'fee':
                self['fee'] = LBRYFeeValidator(metadata.pop('fee'))
            elif k in metadata:
                self.update({k: metadata.pop(k)})

    def _load_fee(self, metadata):
        if 'fee' in metadata:
            self['fee'] = LBRYFeeValidator(metadata.pop('fee'))

    def _verify_sources(self, metadata):
        assert "sources" in metadata, "No sources given"
        for source in metadata['sources']:
            assert source in SOURCE_TYPES, "Unknown source type"

    def _verify_metadata(self, metadata):
        for version in METADATA_REVISIONS:
            self._load_revision(version, metadata)
            if not metadata:
                self.meta_version = version
                break
        assert metadata == {}, "Unknown metadata keys: %s" % json.dumps(metadata.keys())

@@ -132,16 +132,47 @@
 RENCIES%0A
+from lbrynet.core import utils%0A
 import l
@@ -5510,32 +5510,190 @@
 rsion = version%0A
+                if utils.version_is_greater_than(self.meta_version, %220.0.1%22):%0A                    assert self.meta_version == self%5B'ver'%5D, %22version mismatch%22%0A
                 

make sure claimed ver is true