import sys
import logging

from pytest import main as pytest_main
from django.conf import settings, global_settings
from django.core.management.base import BaseCommand

import otree.bots.runner

import otree.common_internal

logger = logging.getLogger('otree')

from otree.constants_internal import AUTO_NAME_BOTS_EXPORT_FOLDER

from sys import exit as sys_exit

MSG_BOTS_HELP = 'Run oTree bots'

class Command(BaseCommand):
    help = MSG_BOTS_HELP

    def _get_action(self, parser, signature):
        option_strings = list(signature)
        for idx, action in enumerate(parser._actions):
            if action.option_strings == option_strings:
                return parser._actions[idx]

    def add_arguments(self, parser):
        # Positional arguments
        parser.add_argument(
            'session_config_name', nargs='?',
            help='If omitted, all sessions in SESSION_CONFIGS are run'
        )

        parser.add_argument(
            'num_participants', type=int, nargs='?',
            help='Number of participants (if omitted, use num_demo_participants)'
        )

        # don't call it --data because then people might think that
        # that's the *input* data folder
        parser.add_argument(
            '--export',
            nargs='?',
            const=AUTO_NAME_BOTS_EXPORT_FOLDER,
            dest='export_path',
            help=(
                'Saves the data generated by the tests. '
                'Runs the "export data" command, '
                'outputting the CSV files to the specified directory, '
                'or an auto-generated one.'),
            )
        parser.add_argument(
            '--save',
            nargs='?',
            const=AUTO_NAME_BOTS_EXPORT_FOLDER,
            dest='export_path',
            help=(
                'Alias for --export.'),
            )

        v_action = self._get_action(parser, ("-v", "--verbosity"))
        v_action.default = '1'
        v_action.help = (
            'Verbosity level; 0=minimal output, 1=normal output,'
            '2=verbose output (DEFAULT), 3=very verbose output')

    def prepare_global_state(self):
        '''
        separate function so it's easier to patch
        these are optimizations that are mostly redundant with what
        runtests.py does.
        '''

        # To make tests run faster, autorefresh should be set to True
        # http://whitenoise.evans.io/en/latest/django.html#whitenoise-makes-my-tests-run-slow
        settings.WHITENOISE_AUTOREFRESH = True

        # same hack as in resetdb code
        # because pytest.main() uses the serializer
        # it breaks if the app has migrations but they aren't up to date
        otree.common_internal.patch_migrations_module()

        settings.STATICFILES_STORAGE = global_settings.STATICFILES_STORAGE


    def handle(
            self, *, verbosity,
            **options):
        self.prepare_global_state()

        # '-s' is to see print output
        # --tb=short is to show short tracebacks. I think this is
        # more expected and less verbose.
        # With the default pytest long tracebacks,
        # often the code that gets printed is in otree-core, which is not relevant.
        # also, this is better than using --tb=native, which loses line breaks
        # when a unicode char is contained in the output, and also doesn't get
        # color coded with colorama, the way short tracebacks do.
        argv = [
            otree.bots.runner.__file__,
            '-s',
            '--tb', 'short',
            '--disable-warnings',
            '--show-capture', 'no'
        ]
        if verbosity == 0:
            argv.append('--quiet')
        if verbosity == 2:
            argv.append('--verbose')

        for k in ['session_config_name', 'num_participants', 'export_path']:
            v = options[k]
            if v:
                # if i pass num_participants as an int, I get an error from argparse.
                argv.extend([f'--{k}', str(v)])

        exit_code = pytest_main(argv)

        if not options['export_path']:
            logger.info('Tip: Run this command with the --export flag'
                        ' to save the data generated by bots.')

        # exit with the exit code, so that CI systems can know if
        # the tests succeeded or failed.
        sys_exit(exit_code)
