import uuid
from functools import reduce
from operator import and_, or_

from django.db import models
from django.db.models import Q

from institute.models import Institute
from wikiazma.storage_helper import public_storage
from .utils import default_rates


class QuestionBankFilter:
    def __init__(self, key, order, values):
        self.key = key
        self.order = order
        self.values = values

    @classmethod
    def from_dict(cls, input):
        return cls(key=input["key"], order=input["order"],
                   values=[QuestionBankFilterValue.from_dict(item) for item in input["values"]])

    def to_dict(self) -> dict:
        return {
            "key": self.key,
            "order": self.order,
            "values": [item.to_dict() for item in self.values],
        }


class QuestionBankFilterValue:
    def __init__(self, value, order, stock, children):
        self.value = value
        self.order = order
        self.stock = stock
        self.children = children

    @classmethod
    def from_dict(cls, input):
        return cls(value=input["value"], order=input["order"], stock=input["stock"],
                   children=[QuestionBankFilter.from_dict(item) for item in input["children"]])

    def to_dict(self) -> dict:
        return {
            "value": self.value,
            "order": self.order,
            "stock": self.stock,
            "children": [item.to_dict() for item in self.children],
        }


def modify_question_bank_filters(filters, tags, add_missed_values=True, add_missed_keys=False, stock_step=1):
    if add_missed_keys:
        present_keys = [filter.key for filter in filters]

        for key in tags:
            if key not in present_keys:
                filters.append(QuestionBankFilter(key, len(filters), []))

    for filter in filters:
        if filter.key in tags:
            selected_values = [
                filter_value_obj for filter_value_obj in filter.values if tags[filter.key] == filter_value_obj.value]
            if selected_values:
                for filter_value_obj in selected_values:
                    filter_value_obj.stock += stock_step
                    modify_question_bank_filters(
                        filters=filter_value_obj.children, tags=tags, add_missed_values=add_missed_values, stock_step=stock_step)
            elif add_missed_values:
                filter.values.append(QuestionBankFilterValue(
                    value=tags[filter.key], order=len(filter.values), stock=1, children=[]))

    return filters


QUESTIONBANK_ACCESSIBILITY_PUBLIC = 'public'
QUESTIONBANK_ACCESSIBILITY_PRIVATE = 'private'

QUESTIONBANK_ACCESSIBILITY_CHOICES = (
    (QUESTIONBANK_ACCESSIBILITY_PRIVATE, QUESTIONBANK_ACCESSIBILITY_PRIVATE),
    (QUESTIONBANK_ACCESSIBILITY_PUBLIC, QUESTIONBANK_ACCESSIBILITY_PUBLIC)
)


class QuestionBank(models.Model):
    id = models.UUIDField(primary_key=True, unique=True,
                          db_index=True, default=uuid.uuid4, editable=False)
    name = models.CharField(max_length=100, db_index=True)
    institute = models.ForeignKey(
        Institute, on_delete=models.SET_NULL, db_index=True, null=True, blank=True)
    description = models.TextField(max_length=3000, null=True, blank=True)
    questions_count = models.IntegerField(default=0)
    # public = models.BooleanField(default=False, db_index=True)
    accessibility = models.CharField(
        max_length=100, choices=QUESTIONBANK_ACCESSIBILITY_CHOICES)
    rates = models.JSONField(default=default_rates)
    archived = models.BooleanField(default=False, db_index=True)
    icon = models.ImageField(
        upload_to='question_bank/icons', null=True, blank=True, storage=public_storage)
    poster = models.ImageField(
        upload_to='question_bank/posters', null=True, blank=True, storage=public_storage)
    featured = models.BooleanField(default=False, db_index=True)
    created_at = models.DateTimeField(auto_now_add=True, db_index=True)

    price = models.PositiveIntegerField(default=0)

    # although modified_at is auto_now but it also renews when any of questions which associates with this record changes
    modified_at = models.DateTimeField(auto_now=True, db_index=True)

    _tags = models.JSONField(default=list)
    _filters = models.JSONField(default=list, blank=True)
    filters_template = models.JSONField(default=list, blank=True)

    @property
    def public(self):
        return self.accessibility == QUESTIONBANK_ACCESSIBILITY_PUBLIC

    @property
    def private(self):
        return self.accessibility == QUESTIONBANK_ACCESSIBILITY_PRIVATE

    @property
    def tags(self):
        return [QuestionBankFilter.from_dict(item) for item in self._tags]

    @tags.setter
    def tags(self, inputs):
        self._tags = [input.to_dict() for input in inputs]

    @property
    def filters(self):
        return [QuestionBankFilter.from_dict(item) for item in self._filters]

    @filters.setter
    def filters(self, inputs):
        self._filters = [input.to_dict() for input in inputs]

    def __str__(self):
        return self.name


class QuestionBankDefaultIcon(models.Model):
    id = models.UUIDField(primary_key=True, unique=True,
                          db_index=True, default=uuid.uuid4, editable=False)
    icon = models.ImageField(
        upload_to='question_bank/default_icons', db_index=True, storage=public_storage)
    created_at = models.DateTimeField(auto_now_add=True, db_index=True)


# def update_question_bank_filters_stocks(question_bank, previous_tags, current_tags):
#     previous_tags_set = set([item for item in previous_tags.items()])
#     current_tags_set = set([item for item in current_tags.items()])

#     removed_tags_set = previous_tags_set - current_tags_set
#     inserted_tags_set = current_tags_set - previous_tags_set

#     _filters = question_bank._filters
#     for _filter in _filters:
