#!/usr/bin/env python
# -*- coding: utf-8 -*-
""" TcEx App Init """

import argparse
import json
import os
import sys
import traceback

import requests
import colorama as c

# Python 2 unicode
if sys.version_info[0] == 2:
    reload(sys)
    sys.setdefaultencoding('utf-8')
    get_input = raw_input
else:
    get_input = input


parser = argparse.ArgumentParser()
parser.add_argument('--branch', choices=['master', 'develop'], default='master', help='Git branch.')
parser.add_argument('--action', choices=['create', 'update', 'migrate'], default='create', help='Whether a ' +
                    'new app should be CREATED, an existing app should be UPDATED, or an existing app of ' +
                    'a different format MIGRATED to the new version.')
parser.add_argument('--type', choices=['job', 'playbook'], help='Init a new App.', required=True)
parser.add_argument('--force', action='store_true', help='If true, this will overwrite existing ' +
                    'files in a directory to create a new app.', default=False)
args, extra_args = parser.parse_known_args()


class TcInit(object):
    """Install Required Modules for App"""

    def __init__(self, _arg):
        """Init TcLib Module"""
        self.args = _arg
        self.app_path = os.getcwd()
        self.base_url = (
            'https://raw.githubusercontent.com/ThreatConnect-Inc/tcex/{}/app_init/'.format(
                self.args.branch))
        self.exit_code = 0
        self.confirm_overwrite = True

        # initialize colorama
        c.init(autoreset=True, strip=False)

        if self.args.action == 'update' or self.args.action == 'migrate':
            # check if the current directory is empty (if so, a RuntimeWarning is raised)
            self._check_empty_app_dir()
            if self.args.action == 'update':
                self.confirm_overwrite = False

        if self.args.force:
            self.confirm_overwrite = False

    def _check_empty_app_dir(self):
        """Check to see if the directory in which the app is going to be created is empty."""
        # if we are updating/migrating an app and the directory is empty - raise a warning
        if not any(os.listdir(self.app_path)):
            message = 'No app exists in this directory. Try using "tcinit --type ' + \
                      '{} --action create --branch '.format(self.args.type) + \
                      '{}" to create an app.'.format(self.args.branch)
            raise RuntimeWarning(message)

    @staticmethod
    def _print_results(file, status):
        """Print the download results."""
        file_color = c.Fore.GREEN
        status_color = c.Fore.RED
        if status == 'Success':
            status_color = c.Fore.GREEN
        print(
            '{}{!s:<20}{}{!s:<35}{}{!s:<15}{}{!s:<15}'.format(
                c.Fore.CYAN, 'Downloading:', file_color, file, c.Fore.CYAN, 'Status:', status_color,
                status))

    @staticmethod
    def _file_exists(file_path):
        """Check if a file at the given path exists."""
        return os.access(file_path, os.F_OK)

    def _confirm_overwrite(self, file_path):
        """Make sure the user would like to continue downloading a file which will overwrite a file in the current directory."""
        message = '\n{}Would you like to overwrite the contents of {} (y/n)? '.format(c.Fore.YELLOW, file_path)
        response = get_input(message)
        response = response.lower()

        if response in ['y', 'yes']:
            return True
        elif response not in ['n', 'no']:
            print('{}{}Please enter "y"/"yes" or "n"/"no"... try again:'.format(c.Style.BRIGHT, c.Fore.RED, file_path))
            return self._confirm_overwrite(file_path)
        return False

    def download_file(self, remote_filename, local_filename=None):
        """Download file from github."""
        status = 'Failed'
        if local_filename is None:
            local_filename = remote_filename

        if self.confirm_overwrite and self._file_exists(local_filename):
            if not self._confirm_overwrite(local_filename):
                print('{}{!s:<20}{}'.format(c.Fore.YELLOW, 'Skipping:', local_filename))
                return

        # github url
        url = '{}{}'.format(self.base_url, remote_filename)
        r = requests.get(url, allow_redirects=True)
        if r.ok:
            open(local_filename, 'wb').write(r.content)
            status = 'Success'
        else:
            print('{}{}Error requesting: {}'.format(c.Style.BRIGHT, c.Fore.RED, url))

        # print download status
        self._print_results(local_filename, status)


if __name__ == '__main__':
    try:
        tci = TcInit(args)
        print('{}{}Using files from "{}" branch'.format(c.Style.BRIGHT, c.Fore.WHITE, args.branch))

        # create a new app OR migrate an app of a different form to the new app format
        if args.action == 'create' or args.action == 'migrate':
            # init files for a new App
            tci.download_file('__main__.py')
            tci.download_file('gitignore', '.gitignore')
            tci.download_file('README.md')
            tci.download_file('requirements.txt')
            tci.download_file('setup.cfg')
            tci.download_file('tcex_json_schema.json')

            if args.type == 'job':
                tci.download_file('job/app.py', 'app.py')
                tci.download_file('job/args.py', 'args.py')
                tci.download_file('job/install.json', 'install.json')
                tci.download_file('job/job_app.py', 'job_app.py')
                tci.download_file('job/run.py', 'run.py')
                tci.download_file('job/tcex.json', 'tcex.json')
            elif args.type == 'playbook':
                tci.download_file('playbook/app.py', 'app.py')
                tci.download_file('playbook/args.py', 'args.py')
                tci.download_file('playbook/install.json', 'install.json')
                tci.download_file('playbook/playbook_app.py', 'playbook_app.py')
                tci.download_file('playbook/run.py', 'run.py')
                tci.download_file('playbook/tcex.json', 'tcex.json')

            # if we are migrating, update the install.json
            if args.action == 'migrate':
                with open('install.json', 'r') as f:
                    install_json = json.load(f)

                if install_json.get('programMain'):
                    install_json['programMain'] = 'run'

                if install_json.get('features'):
                    if 'appBuilderCompliant' not in install_json['features']:
                        install_json['features'].append('appBuilderCompliant')
                else:
                    install_json['features'] = ['appBuilderCompliant']

                with open('install.json', 'w') as f:
                    json.dump(install_json, f, indent=4, sort_keys=True)
        # update the standard files
        elif args.action == 'update':
            # update standard files
            tci.download_file('__main__.py')
            tci.download_file('gitignore', '.gitignore')
            tci.download_file('setup.cfg')
            tci.download_file('tcex_json_schema.json')
            if args.type == 'job':
                tci.download_file('job/job_app.py', 'job_app.py')
                tci.download_file('job/run.py', 'run.py')
            elif args.type == 'playbook':
                tci.download_file('playbook/playbook_app.py', 'playbook_app.py')
                tci.download_file('playbook/run.py', 'run.py')
        sys.exit()

    except Exception as e:
        # TODO: Update this, possibly raise
        print('{}{}{}'.format(c.Style.BRIGHT, c.Fore.RED, traceback.format_exc()))
        sys.exit(1)
