#!/usr/bin/python3


import argparse
import datetime

import colors
import optionalpha
import printing


MEGAPHONE_EMOJI = '\U0001f4e3'
EXPECTED_RANGE_WIDTH = 19


def FormatEarnings(earnings_date):
  if earnings_date is None:
    return ''
  today = datetime.date.today()
  if (earnings_date - today).days < 8:
    return f'{earnings_date} {MEGAPHONE_EMOJI}'
  return str(earnings_date)


def FormatExpectedRange(lower, upper):
  lower_str = '{:.2f}'.format(lower)
  upper_str = '{:.2f}'.format(upper)
  pad_size = EXPECTED_RANGE_WIDTH - 2 - len(lower_str) - len(upper_str)
  return '[{}{}{}]'.format(lower_str, '-'.center(pad_size), upper_str)


def main(args):
  headers = ['TICKER', 'IV RANK', 'PRICE', 'EXPECTED MONTH RANGE', 'EARNINGS']
  widths = [6, 7, 7, EXPECTED_RANGE_WIDTH, 12]
  if args.allranges:
    headers.insert(3, 'EXPECTED WEEK RANGE')
    widths.insert(3, EXPECTED_RANGE_WIDTH)
    headers.insert(3, 'EXPECTED DAY RANGE')
    widths.insert(3, EXPECTED_RANGE_WIDTH)
  printer = printing.TabularPrinter(headers=headers, widths=widths)
  watch_list = optionalpha.GetWatchList(live=args.live)
  show_high = show_mid = show_low = True
  if any((args.highrank, args.midrank, args.lowrank)):
    show_high = args.highrank
    show_mid = args.midrank
    show_low = args.lowrank
  def rows():
    for item in watch_list:
      # If a list of tickers was given, only show those
      if args.tickers and item.ticker not in args.tickers:
        continue

      # Selectively show and paint according to rank level
      if item.rank < 30:
        if not show_low:
          continue
        paint = colors.PaintLightRed
      elif item.rank >= 30 and item.rank < 50:
        if not show_mid:
          continue
        paint = colors.PaintLightYellow
      else:
        if not show_high:
          continue
        paint = colors.PaintLightCyan

      # Create output line
      line = [paint(item.ticker),
              paint(item.rank),
              paint('{:.2f}'.format(item.price)),
              paint(FormatExpectedRange(*item.expected_ranges['month'])),
              paint(FormatEarnings(item.earnings_date))]
      if args.allranges:
        line.insert(3, paint(FormatExpectedRange(*item.expected_ranges['week'])))
        line.insert(3, paint(FormatExpectedRange(*item.expected_ranges['day'])))
      yield line
  printer.print(rows())


if __name__ == '__main__':
  parser = argparse.ArgumentParser(add_help=False)
  parser.add_argument('tickers', nargs='*', help='Display only these tickers off the watch-list.')
  parser.add_argument('--lowrank', '-l', action='store_true', help='Display low-IV rank (0-30).')
  parser.add_argument('--midrank', '-m', action='store_true', help='Display mid-IV rank (30-50).')
  parser.add_argument('--highrank', '-h', action='store_true', help='Display high-IV rank (50-100).')
  parser.add_argument('--allranges', '-a', action='store_true', help='Display day, week and month expected ranges.')
  parser.add_argument('--live', action='store_true', help='Fetch live results (skip cache).')
  parser.add_argument('--help', action='help', help='show this help message and exit')
  args = parser.parse_args()
  main(args)
