from decimal import Decimal

from django.shortcuts import redirect
from django.utils.translation import ugettext_lazy as _
from django.urls import reverse
from constance import config as site_config

from .base import BackendBase


class BitcoinBackend(BackendBase):
    """ Bitcoin backend.
    Connects to a bitcoind.
    """
    backend_id = 'bitcoin'
    backend_verbose_name = _("Bitcoin")
    backend_display_name = _("Bitcoin")

    COIN = 100000000

    def __init__(self, settings):
        from bitcoin import SelectParams
        from bitcoin.rpc import Proxy

        self.account = settings.get('account', 'ccvpn3')

        chain = settings.get('chain')
        if chain:
            SelectParams(chain)

        self.url = settings.get('url')
        if not self.url:
            return

        self.make_rpc = lambda: Proxy(self.url)
        self.rpc = self.make_rpc()
        self.backend_enabled = True

    @property
    def btc_value(self):
        return site_config.BTC_EUR_VALUE

    def new_payment(self, payment):
        rpc = self.make_rpc()

        # bitcoins amount = (amount in cents) / (cents per bitcoin)
        btc_price = round(Decimal(payment.amount) / self.btc_value, 5)

        address = str(rpc.getnewaddress(self.account))

        msg = _("Please send %(amount)s BTC to %(address)s")
        payment.status_message = msg % dict(amount=str(btc_price), address=address)
        payment.backend_extid = address
        payment.backend_data = dict(btc_price=str(btc_price), btc_address=address)
        payment.save()
        return redirect(reverse('payments:view', args=(payment.id,)))

    def check(self, payment):
        rpc = self.make_rpc()

        if payment.status != 'new':
            return

        btc_price = payment.backend_data.get('btc_price')
        address = payment.backend_data.get('btc_address')
        if not btc_price or not address:
            return

        btc_price = Decimal(btc_price)

        received = Decimal(rpc.getreceivedbyaddress(address)) / self.COIN
        payment.paid_amount = int(received * self.btc_value)
        payment.backend_data['btc_paid_price'] = str(received)

        if received >= btc_price:
            payment.user.vpnuser.add_paid_time(payment.time)
            payment.user.vpnuser.on_payment_confirmed(payment)
            payment.user.vpnuser.save()

            payment.status = 'confirmed'

        payment.save()

    def get_info(self):
        rpc = self.make_rpc()

        try:
            info = rpc.getinfo()
            if not info:
                return [(_("Status"), "Error: got None")]
        except Exception as e:
            return [(_("Status"), "Error: " + repr(e))]
        v = info.get('version', 0)
        return (
            (_("Bitcoin value"), "%.2f €" % (self.btc_value / 100)),
            (_("Testnet"), info['testnet']),
            (_("Balance"), '{:f}'.format(info['balance'] / self.COIN)),
            (_("Blocks"), info['blocks']),
            (_("Bitcoind version"), '.'.join(str(v // 10 ** (2 * i) % 10 ** (2 * i))
                                             for i in range(3, -1, -1))),
        )

    def get_ext_url(self, payment):
        if not payment.backend_extid:
            return None
        return 'https://blockstream.info/address/%s' % payment.backend_extid


