"""This module holds the command to find and flag the potential duplicated users"""

from django.core.management.base import BaseCommand, CommandError

from mtp.apps.accounts.models import MTPUser


class Command(BaseCommand):
    """Django command to find and flag the potential duplicated users"""

    help = 'Find and flag the potential duplicated users'

    def add_arguments(self, parser):
        """Add the dryrun, verbose and noinput arguments

        For the parameters, see ``django.core.management.base.BaseCommand``

        """

        parser.add_argument('--dryrun',
                            action='store_true',
                            help='Do not flag the potential duplicated users, only find them')
        parser.add_argument('--verbose',
                            action='store_true',
                            help='Do not show any message')
        parser.add_argument('--noinput',
                            action='store_false',
                            dest='interactive',
                            default=True,
                            help='Do NOT prompt the user for input of any kind.')

    def handle(self, *args, **options):
        """Execute the command with the provided arguments

        For the parameters, see ``django.core.management.base.BaseCommand``

        """

        # Iterate in all the non-deleted users with a non-empty external_id
        queryset = MTPUser.objects.non_deleted().exclude(external_id='')
        user_count = queryset.count()

        # First, display the number of users we are about to iterate on
        if options['verbose']:

            self.stdout.write(
                self.style.WARNING(
                    'About to iterate on %d users to find the potential duplicates' % (
                        user_count
                    )
                )
            )

        if options['interactive']:
            # Ask for the user's agreement
            message = list('\n')
            message.append("Type 'y' to continue, or anything else to cancel: ")

            # If we got an input different from "yes", cancel the command
            if not self.get_input(message) == 'y':
                raise CommandError('Command cancelled.')

        potential_duplicate_users_count = 0
        potential_original_users_count = 0

        for current_index, user in enumerate(queryset):
            potential_duplicates = MTPUser.objects.get_potential_duplicates(user)

            if options['verbose'] and potential_duplicates:

                potential_original_users_count += 1

                self.stdout.write(
                    '[%(current_index)d/%(total_nb)d] '
                    'Found %(potential_duplicates_nb)d potential duplicates for user %(user)s:' % {
                        'current_index': current_index,
                        'total_nb': user_count,
                        'potential_duplicates_nb': len(potential_duplicates),
                        'user': user
                    }
                )

            # For each potential duplicates
            for potential_duplicate_user, reason in potential_duplicates.items():

                potential_duplicate_users_count += 1

                # Output a nice message
                if options['verbose']:
                    self.stdout.write(
                        '- %s - %s' % (
                            potential_duplicate_user, reason.display
                        )
                    )

                # Store the user into the list of potentials
                if not options['dryrun']:
                    user.flag_user_as_potential_duplicate(
                        potential_duplicate_user, reason
                    )

        if options['verbose'] and potential_duplicate_users_count:
            self.stdout.write(
                'Found %d potential users for %d potential original users' % (
                    potential_duplicate_users_count, potential_original_users_count
                )
            )

    @staticmethod
    def get_input(message):
        """Get the user keyboard input

        Parameters
        ----------
        message: list
            A list of message to display to the user prior to the input

        Returns
        -------
        str: the user text input

        Notes
        -----
        This method is only there to easily mock the user's input

        """

        return input(''.join(message))  # pylint: disable=bad-builtin
