import os
import logging
import argparse
import sys
import signal
import subprocess
from functools import wraps

from dotenv import load_dotenv
load_dotenv(verbose=True)

from app.config import configure_app
from app.bot import TrumpBotScheduler
from app.sentimentbot import SentimentBot

parser = argparse.ArgumentParser(description=r"""
""")


ROOT = os.getcwd()
PID_FILE_PATH = os.path.join(ROOT, 'var/run-dev.pid')
CMDS = []
FNCS = []

try:
    os.setpgrp()

    if not os.path.exists(os.path.dirname(PID_FILE_PATH)):
        os.makedirs(os.path.dirname(PID_FILE_PATH))

    with open(PID_FILE_PATH, 'w+') as file:
        file.write(str(os.getpgrp()) + '\n')

except Exception as e:
    logging.error(e)


def _file_path_sanity_check(*args):
    for path in args:
        if not os.path.exists(path):
            raise Exception('Unable to find file %s' % path)


def _start_client_server(*args, **kwargs):
    cmd = [
        'npm', '--prefix', '%s/client' % ROOT, 'run', 'start'
    ]

    CMDS.append(cmd)


def inject_file_paths(fn):
    requests_path = os.environ.get('REQUESTS_FILE_PATH', 'requests/request.json')
    auth_path = os.environ.get('AUTH_FILE_PATH', 'requests/auth.json')
    _file_path_sanity_check(requests_path, auth_path)

    @wraps(fn)
    def wrapper(*args, **kwargs):
        return fn(requests_path=requests_path, auth_path=auth_path, *args, **kwargs)

    return wrapper


@inject_file_paths
def _initialize_trump_bot(auth_path, requests_path, 
                          send_posts: bool=True,
                          *args, **kwargs) -> TrumpBotScheduler:

    trump_bot: TrumpBotScheduler = None
    if send_posts:
        logging.info('Post requests are not being sent.')

        class PostOverride(TrumpBotScheduler):
            def __init__(self, *args, **kwargs):
                super().__init__(*args, **kwargs)

            def __send_tweet_msg__(self, content, headers=None):
                return 200
        
        trump_bot = PostOverride(file_path=requests_path, auth_file_path=auth_path)

    else:
        trump_bot = TrumpBotScheduler(file_path=requests_path, auth_file_path=auth_path)


    # this functions initialize the trump bot by getting the latest tweets
    # and trying to send any tweets that contained errors
    trump_bot.send_latest_tweets()
    trump_bot.resend_bad_tweets()
    logging.info('Trump bot initialization finished... please press ctrl-c to close program if finished.')
    return trump_bot


@inject_file_paths
def _start_sentiment_bot(auth_path: str, requests_path: str, 
                         trump_bot: TrumpBotScheduler, 
                         send_posts: bool=True) -> SentimentBot:

    bot: SentimentBot = None
    if send_posts:
        logging.info('Sentiment bot is not running')

        class PostOverride(SentimentBot):
            def __init__(self, *args, **kwargs):
                super().__init__(*args, **kwargs)

            def __send_tweet_msg__(self, content) -> int:
                return 200

        bot = PostOverride(file_path=requests_path, auth_file_path=auth_path)
    
    else:
        bot = SentimentBot(auth_file_path=auth_path, file_path=requests_path)

    trump_bot.add_job(bot.send_todays_tone, 'interval', hours=24, max_instances=1)
    return bot


def _start_flask_server(*args, **kwargs):
    from app import app

    logging.info('Starting the flask server...')
    level = os.environ.get('CONFIG_LEVEL')

    configure_app(app, status='production' if level is None else level)
    port = app.config.get('PORT')
    app.run(host='0.0.0.0', port=port)  


def _start_dev_server(*args, **kwargs):
    _start_client_server()

    FNCS.append(_start_flask_server)


def _start_prod_server(*args, **kwargs):
    _start_trump_bot(*args, **kwargs)
    _start_flask_server(*args, **kwargs)


def _start_trump_bot(send_posts=True, start_sentiment_bot=False, *args, **kwargs):
    logging.info('Starting the trump bot...')
    # requests_path = os.environ.get('REQUESTS_FILE_PATH', 'requests/request.json')
    # auth_path = os.environ.get('AUTH_FILE_PATH', 'requests/auth.json')
    # _file_path_sanity_check(requests_path, auth_path)

    bot = _initialize_trump_bot(send_posts=send_posts)
    if not start_sentiment_bot: 
        _start_sentiment_bot(trump_bot=bot, send_posts=send_posts)

    bot.start()


ACTIONS = {
    "initialize": _initialize_trump_bot,
    "client": _start_client_server,
    "trumpbot": _start_trump_bot,
    "flask": _start_flask_server,
    "dev": _start_dev_server,
    "prod": _start_prod_server,
}


parser.add_argument('action',
                    help='start the Flask app',
                    type=str,
                    choices=[key for key, v in ACTIONS.items()])

parser.add_argument('-np', '--no-post',
                    dest='send_posts',
                    action='store_true',
                    help='Do not send post requests')

parser.add_argument('-nsb', '--no-sentiment-bot',
                    dest='start_sentiment_bot',
                    action='store_true',
                    help='Do not to start the sentiment bot')


def signal_handler(sig, frame):
    os.killpg(0, signal.SIGTERM)
    os.remove(PID_FILE_PATH)
    sys.exit(0)


def main():
    options = parser.parse_args()
    for s in (signal.SIGINT, signal.SIGTERM):
        signal.signal(s, signal_handler)
    
    ACTIONS.get(options.action)(**options.__dict__)
    env = os.environ.copy()
    for cmd in CMDS:
        subprocess.Popen(cmd, env=env)

    for fn in FNCS:
        subprocess.Popen(fn(), env=env)

    signal.pause()


if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO)
    main()

[((10, 0, 10, 25), 'dotenv.load_dotenv', 'load_dotenv', (), '', False, 'from dotenv import load_dotenv\n'), ((16, 9, 17, 4), 'argparse.ArgumentParser', 'argparse.ArgumentParser', (), '', False, 'import argparse\n'), ((20, 7, 20, 18), 'os.getcwd', 'os.getcwd', ({}, {}), '()', False, 'import os\n'), ((21, 16, 21, 53), 'os.path.join', 'os.path.join', ({(21, 29, 21, 33): 'ROOT', (21, 35, 21, 52): '"""var/run-dev.pid"""'}, {}), "(ROOT, 'var/run-dev.pid')", False, 'import os\n'), ((26, 4, 26, 16), 'os.setpgrp', 'os.setpgrp', ({}, {}), '()', False, 'import os\n'), ((53, 20, 53, 81), 'os.environ.get', 'os.environ.get', ({(53, 35, 53, 55): '"""REQUESTS_FILE_PATH"""', (53, 57, 53, 80): '"""requests/request.json"""'}, {}), "('REQUESTS_FILE_PATH', 'requests/request.json')", False, 'import os\n'), ((54, 16, 54, 70), 'os.environ.get', 'os.environ.get', ({(54, 31, 54, 47): '"""AUTH_FILE_PATH"""', (54, 49, 54, 69): '"""requests/auth.json"""'}, {}), "('AUTH_FILE_PATH', 'requests/auth.json')", False, 'import os\n'), ((57, 5, 57, 14), 'functools.wraps', 'wraps', ({(57, 11, 57, 13): 'fn'}, {}), '(fn)', False, 'from functools import wraps\n'), ((90, 4, 90, 106), 'logging.info', 'logging.info', ({(90, 17, 90, 105): '"""Trump bot initialization finished... please press ctrl-c to close program if finished."""'}, {}), "(\n    'Trump bot initialization finished... please press ctrl-c to close program if finished.'\n    )", False, 'import logging\n'), ((122, 4, 122, 48), 'logging.info', 'logging.info', ({(122, 17, 122, 47): '"""Starting the flask server..."""'}, {}), "('Starting the flask server...')", False, 'import logging\n'), ((123, 12, 123, 42), 'os.environ.get', 'os.environ.get', ({(123, 27, 123, 41): '"""CONFIG_LEVEL"""'}, {}), "('CONFIG_LEVEL')", False, 'import os\n'), ((125, 4, 125, 71), 'app.config.configure_app', 'configure_app', (), '', False, 'from app.config import configure_app\n'), ((126, 11, 126, 33), 'app.app.config.get', 'app.config.get', ({(126, 26, 126, 32): '"""PORT"""'}, {}), "('PORT')", False, 'from app import app\n'), ((127, 4, 127, 38), 'app.app.run', 'app.run', (), '', False, 'from app import app\n'), ((142, 4, 142, 45), 'logging.info', 'logging.info', ({(142, 17, 142, 44): '"""Starting the trump bot..."""'}, {}), "('Starting the trump bot...')", False, 'import logging\n'), ((181, 4, 181, 32), 'os.killpg', 'os.killpg', ({(181, 14, 181, 15): '(0)', (181, 17, 181, 31): 'signal.SIGTERM'}, {}), '(0, signal.SIGTERM)', False, 'import os\n'), ((182, 4, 182, 28), 'os.remove', 'os.remove', ({(182, 14, 182, 27): 'PID_FILE_PATH'}, {}), '(PID_FILE_PATH)', False, 'import os\n'), ((183, 4, 183, 15), 'sys.exit', 'sys.exit', ({(183, 13, 183, 14): '(0)'}, {}), '(0)', False, 'import sys\n'), ((192, 10, 192, 27), 'os.environ.copy', 'os.environ.copy', ({}, {}), '()', False, 'import os\n'), ((199, 4, 199, 18), 'signal.pause', 'signal.pause', ({}, {}), '()', False, 'import signal\n'), ((203, 4, 203, 43), 'logging.basicConfig', 'logging.basicConfig', (), '', False, 'import logging\n'), ((35, 4, 35, 20), 'logging.error', 'logging.error', ({(35, 18, 35, 19): 'e'}, {}), '(e)', False, 'import logging\n'), ((71, 8, 71, 57), 'logging.info', 'logging.info', ({(71, 21, 71, 56): '"""Post requests are not being sent."""'}, {}), "('Post requests are not being sent.')", False, 'import logging\n'), ((83, 20, 83, 88), 'app.bot.TrumpBotScheduler', 'TrumpBotScheduler', (), '', False, 'from app.bot import TrumpBotScheduler\n'), ((101, 8, 101, 52), 'logging.info', 'logging.info', ({(101, 21, 101, 51): '"""Sentiment bot is not running"""'}, {}), "('Sentiment bot is not running')", False, 'import logging\n'), ((113, 14, 113, 77), 'app.sentimentbot.SentimentBot', 'SentimentBot', (), '', False, 'from app.sentimentbot import SentimentBot\n'), ((189, 8, 189, 40), 'signal.signal', 'signal.signal', ({(189, 22, 189, 23): 's', (189, 25, 189, 39): 'signal_handler'}, {}), '(s, signal_handler)', False, 'import signal\n'), ((194, 8, 194, 38), 'subprocess.Popen', 'subprocess.Popen', (), '', False, 'import subprocess\n'), ((28, 26, 28, 56), 'os.path.dirname', 'os.path.dirname', ({(28, 42, 28, 55): 'PID_FILE_PATH'}, {}), '(PID_FILE_PATH)', False, 'import os\n'), ((29, 20, 29, 50), 'os.path.dirname', 'os.path.dirname', ({(29, 36, 29, 49): 'PID_FILE_PATH'}, {}), '(PID_FILE_PATH)', False, 'import os\n'), ((40, 15, 40, 35), 'os.path.exists', 'os.path.exists', ({(40, 30, 40, 34): 'path'}, {}), '(path)', False, 'import os\n'), ((32, 23, 32, 35), 'os.getpgrp', 'os.getpgrp', ({}, {}), '()', False, 'import os\n')]