from django.contrib.auth import get_user_model
from django.db import models
from django.db.models import Q

from books.models import Chapter, ContentBlock, ContentBlockSnapshot
from core.logger import get_logger
from objectives.models import ObjectiveSnapshot
from users.models import User, SchoolClass

logger = get_logger(__name__)


class ChapterSnapshot(models.Model):
    """
    Captures the state of a chapter at the time when the snapshot was taken, for the school class that was selected
    for the user creating the snapshot
    """
    chapter = models.ForeignKey(
        'books.Chapter',
        related_name='chapter_snapshots',
        on_delete=models.PROTECT
    )
    snapshot = models.ForeignKey(
        'books.Snapshot',
        related_name='chapter_snapshots',
        on_delete=models.CASCADE
    )
    title_hidden = models.BooleanField(default=False)
    description_hidden = models.BooleanField(default=False)


class ObjectiveGroupSnapshot(models.Model):
    objective_group = models.ForeignKey(
        'objectives.ObjectiveGroup',
        on_delete=models.CASCADE
    )
    snapshot = models.ForeignKey(
        'books.Snapshot',
        related_name='objective_group_snapshots',
        on_delete=models.CASCADE
    )
    hidden = models.BooleanField(default=False)


class SnapshotManager(models.Manager):
    def create_snapshot(self, module, school_class, user, *args, **kwargs):
        snapshot = self.create(module=module, creator=user, *args, **kwargs)
        chapters = Chapter.get_by_parent(module)
        for chapter in chapters:
            ChapterSnapshot.objects.create(
                chapter=chapter,
                snapshot=snapshot,
                title_hidden=chapter.title_hidden_for.filter(id=school_class.id).exists(),
                description_hidden=chapter.description_hidden_for.filter(id=school_class.id).exists()
            )
            base_qs = ContentBlock.get_by_parent(chapter).filter(contentblocksnapshot__isnull=True)
            for content_block in base_qs.filter(user_created=False):
                if content_block.hidden_for.filter(id=school_class.id).exists():
                    snapshot.hidden_content_blocks.add(content_block)
            for content_block in base_qs.filter(Q(user_created=True) & Q(owner=user)):
                new_content_block = ContentBlockSnapshot(
                    hidden=content_block.is_hidden_for_class(school_class),
                    snapshot=snapshot,
                    contents=content_block.contents,
                    type=content_block.type,
                    title=content_block.title,
                    original_creator=content_block.owner
                )
                content_block.add_sibling(instance=new_content_block, pos='right')
                revision = new_content_block.save_revision()
                revision.publish()
                new_content_block.save()

        for objective_group in module.objective_groups.all():
            ObjectiveGroupSnapshot.objects.create(
                objective_group=objective_group,
                snapshot=snapshot,
                hidden=objective_group.hidden_for.filter(id=school_class.id).exists(),
            )
            base_qs = objective_group.objectives.filter(objectivesnapshot__isnull=True)
            for objective in base_qs.filter(owner__isnull=True):
                if objective.hidden_for.filter(id=school_class.id).exists():
                    snapshot.hidden_objectives.add(objective)
            for objective in base_qs.filter(owner=user):
                ObjectiveSnapshot.objects.create(
                    hidden=objective.is_hidden_for_class(school_class=school_class),
                    snapshot=snapshot,
                    text=objective.text,
                    group=objective_group,
                    order=objective.order
                )

        return snapshot


class Snapshot(models.Model):
    module = models.ForeignKey(
        'books.Module',
        on_delete=models.PROTECT,
        related_name='snapshots'
    )
    chapters = models.ManyToManyField(
        'books.Chapter',
        through=ChapterSnapshot
    )
    hidden_content_blocks = models.ManyToManyField(
        'books.ContentBlock',
        related_name='hidden_for_snapshots'
    )
    created = models.DateTimeField(auto_now_add=True)
    creator = models.ForeignKey(get_user_model(), on_delete=models.SET_NULL, null=True)
    shared = models.BooleanField(default=False)
    objective_groups = models.ManyToManyField(
        'objectives.ObjectiveGroup',
        through=ObjectiveGroupSnapshot,
        related_name='+'
    )
    hidden_objectives = models.ManyToManyField(
        'objectives.Objective',
        related_name='hidden_for_snapshots'
    )

    objects = SnapshotManager()

    def __str__(self):
        return f'Snapshot {self.id}'

    def reset(self, user: User, selected_class: SchoolClass):
        for chapter in Chapter.get_by_parent(self.module):
            qs = ContentBlock.get_by_parent(chapter)
            default_content = Q(user_created=False)
            no_snapshot = Q(contentblocksnapshot__isnull=True)
            owner_user = Q(owner=user)
            logger.info(f'resetting hidden properties for chapter {chapter.id}')
            chapter.title_hidden_for.remove(selected_class)
            chapter.description_hidden_for.remove(selected_class)

            for content_block in qs.filter(default_content & no_snapshot):
                content_block.hidden_for.remove(selected_class)
            for content_block in qs.filter(owner_user):
                content_block.visible_for.remove(selected_class)

    def apply(self, user: User, selected_class: SchoolClass):
        for content_block in self.hidden_content_blocks.all():
            content_block.hidden_for.add(selected_class)
        for custom_content_block in self.custom_content_blocks.all():
            custom_content_block.to_regular_content_block(owner=user, school_class=selected_class)
        for chapter_snapshot in ChapterSnapshot.objects.filter(snapshot=self):
            chapter = chapter_snapshot.chapter
            if chapter_snapshot.title_hidden:
                chapter.title_hidden_for.add(selected_class)
            if chapter_snapshot.description_hidden:
                chapter.description_hidden_for.add(selected_class)
        for objective_group_snapshot in self.objective_groups.through.objects.all():
            if objective_group_snapshot.hidden:
                objective_group_snapshot.objective_group.hidden_for.add(selected_class)
        for objective in self.hidden_objectives.all():
            objective.hidden_for.add(selected_class)
        for custom_objective in self.custom_objectives.all():
            custom_objective.to_regular_objective(owner=user, school_class=selected_class)
