import itertools

from django.contrib.auth import get_user_model
from django.core.management.base import NoArgsCommand, CommandError
from django.db.models import Q

from guardian.shortcuts import assign_perm

from ldt.ldt_utils.models  import Project, Content
from ldt.ldt_utils.modelsutils  import ProjectMerger

# TODO: prefix decouspage by user name if needed.
class Command(NoArgsCommand):
    """
    Merge projects.
    Beware this version of the command correctly support merging projects from only one content.
    Usage:
        -p <project_id>: project id, can have more than one
        -c <content_id>: content id, can have more than one
        -t <title>: project title (default merge of "projects title")
        -u <user>: user for project (defaut admin)
        --only-visible: only visible cuttings (default false)
        --exclude-shot-by-shot: remove shot by shot (default false)
        --all-published: merge all projects published or not (default false)
    """
    help = 'Merge projects'

    def add_arguments(self, parser):

        # Named (optional) arguments
        parser.add_argument(
            '--only-visible',
            action='store_true',
            dest='visible',
            default=False,
            help='merge only visible cuttings')

        parser.add_argument(
            '--exclude-shot-by-shot',
            action='store_true',
            dest='exclude_shot_by_shot',
            default=False,
            help='exclude shot by shot cuttings')

        parser.add_argument(
            '--all-published',
            action='store_true',
            dest='all_published',
            default=False,
            help='merge all projects published or not')

        parser.add_argument(
            '-p', '--project',
            action='append',
            dest='projects',
            metavar='PROJECT_ID',
            default=[],
            help='project id to concatenate')

        parser.add_argument(
            '-c', '--content',
            action='store',
            dest='contents',
            default=None,
            metavar='CONTENT_ID',
            help='content id to concatenate')

        parser.add_argument(
            '-t', '--title',
            action='store',
            dest='title',
            metavar='TITLE',
            help='The title for the merged project. defaut "merged: title1, title2,..."'
        )

        parser.add_argument(
            '-u', '--user',
            action='store',
            dest='user',
            metavar='USER',
            help='The user creator of the merged project'
        )


    def handle_noargs(self, **options):

        # pylint: disable=C0103
        User = get_user_model()

        username = options.get('user', None)

        if not username:
            users = User.objects.filter(is_superuser=True).order_by('date_joined')
            if len(users) > 0:
                user = users[0]
                username = user.username
            else:
                raise CommandError("No username given and can not fond a superuser")
        else:
            user = User.objects.get(username=username)

        # filter projects
        project_filter = Q()

        projects_ids = options.get('projects', None)
        if projects_ids:
            project_filter &= Q(ldt_id__in=projects_ids)

        content_id = options.get('contents', None)
        if content_id:
            project_filter = Q(contents__iri_id__in=[content_id,])

        if not projects_ids and not content_id:
            raise CommandError("At least one content or project must be specified")

        if not options.get('all_published', False):
            project_filter &= Q(state=Project.PUBLISHED)

        projects = Project.objects.filter(project_filter)

        if len(projects) == 0:
            raise CommandError("No project found, aborting")


        title = options.get('title', "")
        if not title:
            title = "Merged: " + ", ".join([p.title.strip() for p in projects])

        contents = set(itertools.chain(*[proj.contents.all() for proj in projects]))
        if len(contents) == 0:
            raise CommandError("Content not found")
        if len(contents) > 1 and not content_id:
            raise CommandError("Too many contents %d" % len(contents))

        if content_id:
            content = Content.objects.get(iri_id=content_id)
        else:
            content = contents[0]

        if options.get('verbosity', 1) > 0:
            print("Merging %d projects in \'%s\'" % (len(projects), title))

        pmerger = ProjectMerger(content, projects)

        proj = pmerger.get_merged_project(
            only_visible=not options.get('visible', False),
            shot_by_shot=not options.get('exclude_shot_by_shot', False))

        proj.created_by = username
        proj.changed_by = username
        proj.owner = user
        proj.title = title
        proj.save()

        assign_perm('view_project', user, proj)
        assign_perm('change_project', user, proj)

        if options.get('verbosity', 1) > 0:
            print("Project \'%s\' created with id '%s'" % (title, proj.ldt_id))
