#!/usr/bin/env python
"""
NAME:
  aboki -

DESCRIPTION:
  Black market currency rate instantly in your terminal! (Powered by AbokiFx:
  https://abokifx.com/).

USAGE:
  aboki recent
  aboki rates <type>
  aboki rate <currency>
  aboki convert <amount> <FROM> <TO>
  aboki test
  aboki (-h | --help)
  aboki --version

OPTIONS:
  <type>      (string) Specify rate type for this operation: cbn, movement,
              lagos_previous, moneygram, westernunion, otherparallel. This
              defaults to 'cbn'.
  <currency>  (string) Specify what currency rate to show.
  <amount>    (float) The amount you'd like to convert.
  <FROM>      (string) Specify the currency you are converting from.
  <TO>        (string) Specify the currency you are converting to.
  -h --help   Show this screen.
  --version   Show version.

EXAMPLES:
  o Convert usd to ngn

    The following convert command converts a currency to a specified currency:

      aboki convert 500 usd ngn

    Output:

      Conversion Successful
      SEE HOW MUCH YOU GET IF YOU SELL
      ================================
      {
        "ngn": 202500.0,
        "rate": 405.0,
        "usd": 500.0
      }
      ================================

  o Retrieve usd rate

    The following rate command retrieves currency current rate:

      aboki rate usd

    Output:

      USD Exchange Rate
      =================
      387.0
      =================

Written by Akinjide Bankole <https://www.akinjide.me/>. Like the software? Star
on Github <https://github.com/akinjide/aboki>
Or... Send a tip to Akinjide: 17AcFdn8kTpGw1R34MC5U5SyZHrMbZK4Sq
"""


from __future__ import absolute_import, print_function
from json import dumps
from sys import exit

from bs4 import BeautifulSoup
from docopt import docopt
from requests import get, post, exceptions
from pkg_resources import get_distribution


# Globals
API_URI = 'https://www.abokifx.com'
VERSION = 'aboki %s' % get_distribution("aboki").version


class Aboki:

  def __init__(self):
    self.currencies = ('usd', 'gbp', 'eur')
    self.types = ['cbn', 'movement', 'lagos_previous', 'moneygram', 'westernunion', 'otherparallel']
    self.quotes = 'Quotes:\t*morning\t**midday\t***evening'
    self.note = '**NOTE**: Buy / Sell => 90 / 100\n'

  def make_request(self, path, params={}, data={}, method='GET'):
    """Make the specified API request, and return the HTML data, or quit
    with an error.
    """

    try:
      if method.lower() == 'post':
        resp = post('%s/%s' % (API_URI, path), params=params, data=dumps(data), headers={'Content-Type': 'application/json'})
      else:
        resp = get('%s/%s' % (API_URI, path), params=params)

      if resp.status_code != 200:
        print('Error connecting. Please try again.')
        print('If the problem persists, please email r@akinjide.me.')
        exit(1)
      return resp.text

    except exceptions.RequestException, e:
        print('Error connecting. Please check network and try again.')
        print('If the problem persists, please email r@akinjide.me.')
        exit(1)

  def parse(self, content):
    soup = BeautifulSoup(content, "html5lib")
    records = soup.select("body .lagos-market-rates table tbody > tr")
    data = [[str(j) for j in record.stripped_strings
             if str(j) not in ('NGN', 'Buy / Sell')] for record in records]
    return {'title': str(soup.title.string), 'data': data}

  def get_current_rate(self):
    """Return the current exchange rate for USD, GBP, EUR."""

    resp = self.make_request('')
    rjson = self.parse(resp)
    rates = ' / '.join(rjson['data'][0][1:]).split(' / ')
    return dict(zip(self.currencies, [float(rate) for rate in rates if '*' not in rate]))

  def recent(self):
    """List recent exchange rates for USD, GBP, EUR."""

    resp = self.make_request('')
    rjson = self.parse(resp)
    underline = '==' * len(rjson['title'])

    print(self.quotes)
    print(self.note)
    print(rjson['title'])
    print(underline)
    print('\t\t\t\t%s\t\t\t%s\t\t%s' % ('USD', 'GBP', 'EUR'))

    for datum in rjson['data']:
      print('\t|\t'.join(datum))

    print(underline)

  def rates(self, type):
    """List current exchange rates.

    Supported types: cbn, movement, lagos_previous, moneygram, westernunion and otherparallel.
    """

    param = None
    if type in self.types:
      param = {'rates': self.types[self.types.index(type)]}
    else:
      print('\nNot sure which type?')
      print('You can specify any of this: '
      'cbn, movement, lagos_previous, moneygram, westernunion or otherparallel\n'
      '[default: cbn]\n')
      param = {'rates': 'cbn'}

    resp = self.make_request('ratetypes', param)
    rjson = self.parse(resp)
    underline = '==' * len(rjson['title'])

    if type in ('otherparallel', 'movement'):
      print(self.quotes)
      print(self.note)
    elif type == 'lagos_previous':
      print(self.note)

    print(rjson['title'])
    print(underline)

    for index, data in enumerate(rjson['data']):
      if index == 0:
        print('\t\t\t%s' % '\t\t\t'.join(data))
      else:
        print('\t|\t'.join(data))

    print(underline)

  def rate(self, currency):
    """List current exchange rate for currency."""

    rates = self.get_current_rate()
    xc = rates.get(currency)

    if xc:
      print('%s Exchange Rate' % (currency.upper()))
      print('================')
      print(xc)
      print('================')
    else:
      print('\nNot sure which type?')
      print('You can specify any of this: usd, gbp, eur or ngn\n')

  def convert(self, amount, FROM, TO):
    """Convert currency with current rate."""

    rates = self.get_current_rate()
    FROM = FROM.strip().lower()
    TO = TO.strip().lower()
    error = 'Oops! You are trying to do something useful.  FROM: %s, TO: %s' % (FROM, TO)

    try:
      assert FROM and TO and 'ngn' in (FROM, TO), error
      assert FROM in self.currencies or TO in self.currencies, error
    except AssertionError, e:
      print(e)
      exit(1)

    ojson = {FROM: amount}
    if FROM == 'ngn':
      ojson[TO] = amount / rates[TO]
      ojson['rate'] = rates[TO]
    elif FROM in self.currencies:
      ojson['ngn'] = amount * rates[FROM]
      ojson['rate'] = rates[FROM]

    print('Conversion Successful')
    print('SEE HOW MUCH YOU GET IF YOU SELL')
    print('================================')
    print(dumps(ojson, sort_keys=True, indent=2, separators=(',', ': ')))
    print('================================')

  def test(self):
    """Test to make sure everything's working."""

    resp = self.make_request('')
    if resp:
      print("Yippe! you've broken nothing!")
    else:
      print("Oops! Catastrophic Failure")
      print('If the problem persists, please email r@akinjide.me.')
      exit(1)


def main():
  """Handle programmer input, and do stuffs."""

  arguments = docopt(__doc__, version=VERSION)
  aboki = Aboki()

  if arguments['recent']:
    aboki.recent()
  elif arguments['rates']:
    aboki.rates(arguments['<type>'])
  elif arguments['rate']:
    aboki.rate(arguments['<currency>'])
  elif arguments['convert']:
    amount = float(arguments['<amount>'])
    aboki.convert(amount, arguments['<FROM>'], arguments['<TO>'])
  elif arguments['test']:
    aboki.test()


if __name__ == '__main__':
  main()
