# -*- coding: future_fstrings -*-
from __future__ import absolute_import
from __future__ import print_function

import os
import sys
import json
import shutil
import argparse
import getpass
import queue
import threading
import collections
import tweebot._base as _base
from handlers import ContestTweetHandler
from tweebot import logger, ua_provider

if sys.version_info[0] < 3:
  logger.error('Python 3 or a more recent version is required.')
  exit()

def _get_searchers(queue, config):
  count = config.get('count', 1)
  result = {'query': config['search-queries']}
  while count > 0:
    searcher = _base.TweetSearcher(queue, **config)
    result.setdefault('searchers', []).append(searcher)
    count -= 1
  return result


def _get_handlers(tweet_queue, action_queue, config):
  count = config.get('count', 1)
  handlers = []
  while count > 0:
    handlers.append(ContestTweetHandler(
      tweet_queue, action_queue, **config
    ))
    count -= 1
  return handlers


def _get_executors(action_queue, **config):
  count = config.get('count', 1)
  executors = []
  while count > 0:
    executors.append(_base.ActionExecutor(
      action_queue, config['request-delay']
    ))
    count -= 1
  return executors


def _spin_handlers(handlers):
  for handler in handlers:
    threading.Thread(
      target=handler.handle
    ).start()


def _spin_searchers(queries, searchers):
  if not isinstance(queries, collections.Iterable):
    queries = (queries, )
  for query in queries:
    for searcher in searchers:
      threading.Thread(
        target=searcher.search,
        args=(query,)
      ).start()


def _spin_executors(executors):
  if not isinstance(executors, collections.Iterable):
    executors = (executors, )
  for executor in executors:
    threading.Thread(
      target=executor.execute
    ).start()


def main():
  parser = argparse.ArgumentParser()
  default_config_path = os.path.join(
    os.path.dirname(__file__), 'config/'
  )

  parser.add_argument(
    '-a', '--agents',
    help='File containing user-agents',
    dest='agents_file',
    default=f'{default_config_path}/user-agents.txt'
  )
  parser.add_argument(
    '-i', '--invalidate',
    help='Invalidate all saved sessions',
    dest='invalidate',
    action='store_true'
  )
  parser.add_argument(
    '-c', '--config',
    help='Configuration file',
    dest='config',
    default=f'{default_config_path}/config.json'
  )
  parser.add_argument(
    '-e', '--executor-count',
    help='How many executors should we have running',
    dest='executor_count',
    default=2
  )

  args = parser.parse_args()

  if args.invalidate:
    _base.clear()

  if args.agents_file:
    ua_provider.load(args.agents_file)

  if not args.config:
    logger.error('You need to provide the path to the config.json file')
    exit()

  config = {}

  try:
    with open(args.config, encoding='UTF-8') as fp:
      config = json.loads(fp.read())
      config['searchers']; config['handlers'] # quick check
  except Exception as ex:
    exit(f'Failed to read config.json .\n {ex}')

  if not 'executors' in config:
    if not args.executor_count:
      logger.error(
        '''You will need to provide configurations
        for the executor object. Check the docs for more info.'''
      )
      exit()
    config['executors'] = [{
      'count': args.executor_count,
      'request-delay': 2
    }]

  while True:
    username = input('Twitter username: ')
    if not _base._is_logged(username):
      password = getpass.getpass(prompt='Twitter password: ')
      try:
        _base.login(username, password)
      except _base.InvalidCredentials:
        logger.error('Invalid credentials.Try again')
        continue
    os.environ['username'] = username
    break

  tweet_queue = queue.Queue()
  action_queue = queue.Queue()

  for params in config['searchers']:
    searcher = _get_searchers(tweet_queue, params)
    _spin_searchers(searcher['query'], searcher['searchers'])

  for params in config['handlers']:
    handler = _get_handlers(tweet_queue, action_queue, params)
    _spin_handlers(handler)

  for params in config['executors']:
    executors = _get_executors(action_queue, **params)
    _spin_executors(executors)

  tweet_queue.join(); action_queue.join()


if __name__ == '__main__':
  main()
