# coding:utf-8
import json
from functools import partial
from django.conf import settings

from gm_dataquery.dict_mixin import to_dict
from gm_dataquery.dataquery import DataSQLQuery, DataBuilder
from gm_dataquery.db import DB
from gm_types.gaia import TOP_CONTENT_RELATED_TYPE

from group.models import Topic, TopicTag, TopicTagV3, TopContent
from group.tasks.tasks import sync_group_topic_extra_by_id
from api.models import Tag


class TopicDB(DataBuilder):

    def getval_tags(self, obj):
        return list(TopicTag.objects.filter(topic_id=obj.id, is_online=True).values_list("tag_id", flat=True))

    def getval_tags_name(self, obj):
        tag_ids = list(TopicTag.objects.filter(topic_id=obj.id, is_online=True).values_list("tag_id", flat=True))
        return ", ".join([i.name for i in Tag.objects.filter(pk__in=tag_ids)])

    def getval_tag_v3_ids(self, obj):
        return list(TopicTagV3.objects.filter(
            topic_id=obj.id,
            is_online=True
        ).values_list("tag_v3_id", flat=True))

    def punch_entrance(self, obj):

        try:
            punch_entrance = json.loads(obj.punch_entrance)
        except:
            punch_entrance = {}

        return punch_entrance

    def getval_punch_entrance_one(self, obj):
        return self.punch_entrance(obj).get("punch_entrance_one", '')

    def getval_punch_entrance_one_url(self, obj):
        return self.punch_entrance(obj).get("punch_entrance_one_url", '')

    def getval_punch_entrance_two(self, obj):
        return self.punch_entrance(obj).get("punch_entrance_two", '')

    def getval_punch_entrance_two_url(self, obj):
        return self.punch_entrance(obj).get("punch_entrance_two_url", '')
    
    def getval_top_contents_length(self, obj):
        return TopContent.objects.filter(
            related_id=obj.id,
            related_type=TOP_CONTENT_RELATED_TYPE.TOPIC,
            is_online=True,
        ).count()


def add_relation_top_content():
    def getval_top_id(self, obj, i=1):

        try:
            return obj.top_contents[i-1]["id"]
        except:
            return None

    def getval_top_theme(self, obj, i=1):

        try:
            return obj.top_contents[i-1]["theme"]
        except:
            return ""

    def getval_top_title(self, obj, i=1):

        try:
            return obj.top_contents[i-1]["title"]
        except:
            return ""

    def getval_top_content_type(self, obj, i=1):

        try:
            return obj.top_contents[i-1]["content_type"]
        except:
            return ""

    def getval_top_content_id(self, obj, i=1):

        try:
            return obj.top_contents[i - 1]["content_id"]
        except:
            return 0

    def f(callable, i):
        def wrap(*args, **kwargs):
            wrap_func = partial(callable, i=i)
            return wrap_func(*args, **kwargs)
        return wrap

    for i in range(1, 20):
        setattr(TopicDB, "getval_top_id_" + str(i), f(getval_top_id, i=i))
        setattr(TopicDB, "getval_top_theme_" + str(i), f(getval_top_theme, i=i))
        setattr(TopicDB, "getval_top_title_" + str(i), f(getval_top_title, i=i))
        setattr(TopicDB, "getval_top_content_type_" + str(i), f(getval_top_content_type, i=i))
        setattr(TopicDB, "getval_top_content_id_" + str(i), f(getval_top_content_id, i=i))

add_relation_top_content()


@DB
class TopicDQ(DataSQLQuery):
    model = Topic
    data_model = TopicDB

    def create(self, **kwargs):
        tags = kwargs.pop('tags')
        tag_v3_ids = kwargs.pop("tag_v3_ids", [])
        kwargs.pop('tags_name', None)
        kwargs.pop('top_contents_length', None)
        top_contents = kwargs.pop('top_contents', [])

        top_card_id = kwargs.get('top_card_id', '')
        if not top_card_id:
            kwargs["top_card_id"] = None

        punch_entrance = {
            "punch_entrance_one": kwargs.pop('punch_entrance_one', ''),
            "punch_entrance_one_url": kwargs.pop('punch_entrance_one_url', ''),
            "punch_entrance_two": kwargs.pop('punch_entrance_two', ''),
            "punch_entrance_two_url": kwargs.pop('punch_entrance_two_url', ''),
        }
        kwargs["punch_entrance"] = json.dumps(punch_entrance)

        topic = Topic.objects.create(**kwargs)
        if tags:
            TopicTag.objects.bulk_create([
                TopicTag(topic_id=topic.id, tag_id=tag_id)
                for tag_id in tags
            ])

        if tag_v3_ids:
            TopicTagV3.objects.bulk_create([
                TopicTagV3(topic_id=topic.id, tag_v3_id=tag_id)
                for tag_id in tag_v3_ids
            ])

        self._update_top_contents(topic.id, top_contents)
        sync_group_topic_extra_by_id.delay(topic.id, _type=TOP_CONTENT_RELATED_TYPE.TOPIC)
        return to_dict(topic)

    def _update_top_contents(self, topic_id, top_contents):
        need_create_top_contents = []
        online_top_ids = set()
        for top_content in top_contents:
            top_id = int(top_content.get("top_id")) if top_content.get("top_id") else 0
            top_theme = top_content.get("top_theme", "")
            top_title = top_content.get("top_title", "")
            content_type = top_content.get("top_content_type", "")
            top_content_id = top_content.get("top_content_id", 0)
            if not top_id:
                need_create_top_contents.append(
                    TopContent(
                        theme=top_theme,
                        title=top_title,
                        content_type=content_type,
                        content_id=top_content_id,
                        related_type=TOP_CONTENT_RELATED_TYPE.TOPIC,
                        related_id=topic_id,
                    )
                )
            else:
                online_top_ids.add(top_id)
                TopContent.objects.update_or_create(
                    id=top_id,
                    defaults=dict(
                        theme=top_theme,
                        title=top_title,
                        content_type=content_type,
                        content_id=top_content_id,
                        related_type=TOP_CONTENT_RELATED_TYPE.TOPIC,
                        related_id=topic_id,
                        is_online=1,
                    )
                )

        all_top_ids = set(
            TopContent.objects.using(settings.SLAVE_DB_NAME).filter(
                related_id=topic_id,
                related_type=TOP_CONTENT_RELATED_TYPE.TOPIC,
            ).values_list('id', flat=True)
        )

        need_offline_top_ids = list(all_top_ids - online_top_ids)
        TopContent.objects.filter(id__in=need_offline_top_ids).update(is_online=False)

        if need_create_top_contents:
            TopContent.objects.bulk_create(need_create_top_contents)

    def _update_tag(self, topic_id, tags):

        if tags == [] or tags:
            TopicTag.objects.filter(topic_id=topic_id).delete()

        if tags:
            TopicTag.objects.bulk_create([
                TopicTag(topic_id=topic_id, tag_id=tag_id)
                for tag_id in tags
            ])

    def _update_tag_v3(self, topic_id, tags):
        if tags == [] or tags:
            TopicTagV3.objects.filter(topic_id=topic_id).delete()

        if tags:
            TopicTagV3.objects.bulk_create([
                TopicTagV3(topic_id=topic_id, tag_v3_id=tag_id)
                for tag_id in tags
            ])

    def update(self, updates, **kwargs):
        tags = updates.pop('tags', None)
        tag_v3_ids = updates.pop("tag_v3_ids", None)
        updates.pop('tags_name', None)
        updates.pop('top_contents_length', None)
        top_contents = updates.pop('top_contents', [])

        top_card_id = updates.get('top_card_id', '')
        if not top_card_id:
            updates["top_card_id"] = None

        topic = Topic.objects.get(**kwargs)

        try:
            punch_entrance = json.loads(topic.punch_entrance)
        except:
            punch_entrance = {}

        def get_punch_entrance_key(k):
            v = punch_entrance.get(k, '')
            if k in updates:
                v = updates.pop(k)
            return v

        punch_entrance_keys = [
            "punch_entrance_one",
            "punch_entrance_one_url",
            "punch_entrance_two",
            "punch_entrance_two_url",
        ]
        for k in punch_entrance_keys:
            punch_entrance[k] = get_punch_entrance_key(k)
        updates["punch_entrance"] = json.dumps(punch_entrance)

        Topic.objects.filter(**kwargs).update(**updates)
        self._update_tag(topic.id, tags)
        self._update_tag_v3(topic.id, tag_v3_ids)
        self._update_top_contents(topic.id, top_contents)

        return 1

