from __future__ import absolute_import
from optparse import make_option
import sys

from behave.configuration import options as behave_options
from behave.__main__ import main as behave_main
from django.core.management.base import BaseCommand

from behave_django.environment import monkey_patch_behave
from behave_django.parser import PassThroughOptionParser
from behave_django.runner import (BehaviorDrivenTestRunner,
                                  ExistingDatabaseTestRunner)


def get_command_options():
    return (
        make_option(
            '--use-existing-database',
            action='store_true',
            default=False,
            help="Don't create a test database. USE AT YOUR OWN RISK!",
        ),
    )


def get_behave_options():
    """Creates options for the behave management command based on behave"""

    new_options = []

    conflicts = [
        '--no-color',
        '--version'
    ]

    for fixed, keywords in behave_options:
        # TODO: accept short options too
        long_option = None
        for option in fixed:
            if option.startswith("--"):
                long_option = option
                break

        # Do not add conflicting options
        if long_option in conflicts:
            continue

        if long_option:
            # type isn't a valid keyword for make_option
            if hasattr(keywords.get('type'), '__call__'):
                del keywords['type']
            # config_help isn't a valid keyword for make_option
            if 'config_help' in keywords:
                del keywords['config_help']

            new_options.append(
                make_option(long_option, **keywords)
            )
    return tuple(new_options)


class Command(BaseCommand):
    help = 'Runs behave tests'
    option_list = BaseCommand.option_list + get_behave_options() + \
        get_command_options()

    def handle(self, *args, **options):
        behave_args = self.get_behave_args()

        # Configure django environment
        if options['dry_run'] or options['use_existing_database']:
            django_test_runner = ExistingDatabaseTestRunner()
        else:
            django_test_runner = BehaviorDrivenTestRunner()
        django_test_runner.setup_test_environment()
        old_config = django_test_runner.setup_databases()

        # Run Behave tests
        monkey_patch_behave(django_test_runner)
        exit_status = behave_main(args=behave_args)

        # Teardown django environment
        django_test_runner.teardown_databases(old_config)
        django_test_runner.teardown_test_environment()

        if exit_status != 0:
            sys.exit(exit_status)

    def get_behave_args(self, argv=sys.argv):
        """Remove command line arguments not accepted by behave."""
        # Override option_list to remove the behave arguments
        orig_option_list = self.option_list
        self.option_list = BaseCommand.option_list + get_command_options()
        # Get an OptionParser from django with the new option_list
        django_parser = self.create_parser('manage.py', 'behave')

        # Put back the original option_list to minimize side effets
        self.option_list = orig_option_list

        # Load the option_list generated by django into our custom parser
        parser = PassThroughOptionParser()
        for option in django_parser.option_list:
            if '--help' not in option._long_opts:
                parser.add_option(option)

        # Our custom parser returns the unrecognized args instead of exploding
        options, args = parser.parse_args(argv[2:])

        # The unrecognized args are for behave :)
        return args
