from collections import defaultdict

import time
from django.core.management import BaseCommand
from django.conf import settings
from gm_types.gaia import TAG_TYPE, TAG_V3_TYPE

from talos.models.diary import (
    Diary,
    DiaryTagV3,
    DiaryTag,
)
from talos.models.topic import (
    Problem,
    ProblemTag,
    ProblemTagV3,
)
from qa.models.answer import (
    Answer,
    AnswerTagV3,
    Question,
    QuestionTagV3,
    AnswerTag,
    QuestionTag,
)
from tags.models.tag import (
    TagV3,
    TagMapOldTag,
    Tag,
)

CONTENT_TYPE_MAP = {
    "diary": (Diary, DiaryTagV3, "diary_id", DiaryTag, 'tag_id'),
    "topic": (Problem, ProblemTagV3, "problem_id", ProblemTag, 'tag_id'),
    "question": (Question, QuestionTagV3, "question_id", QuestionTag, 'tag'),
    "answer": (Answer, AnswerTagV3, "answer_id", AnswerTag, 'tag'),
}


class TagTool(object):

    def __new__(cls, content_type):
        cls.model, cls.tag3_model, cls.field, cls.tag_model, cls.tag_name = CONTENT_TYPE_MAP.get(content_type)
        cls.operation_tag1_ids = getattr(cls, 'get_operation_tag1')()
        cls.operation_tag3_ids = getattr(cls, 'get_operation_tag3')()
        cls.operation_tag3_map_tag1 = getattr(cls, 'operation_tag1_map_tag3')()
        cls.create_info = []
        return cls

    @classmethod
    def get_operation_tag1(cls):
        """所有1.0运营标签"""
        all_operation_tag1 = set(Tag.objects.using(settings.ZHENGXING_DB).filter(
            tag_type=TAG_TYPE.YUNYING, is_online=True,
        ).values_list('id', flat=True))
        return all_operation_tag1

    @classmethod
    def get_operation_tag3(cls):
        """所有3.0运营标签 包括交易运营、社区运营"""
        operation_tag3_ids = set(TagV3.objects.using(settings.ZHENGXING_DB).filter(
            tag_type__in=[TAG_V3_TYPE.EXCHANGE, TAG_V3_TYPE.COMMUNITY], is_online=True
        ).values_list('id', flat=True))
        return operation_tag3_ids

    @classmethod
    def operation_tag1_map_tag3(cls):
        """1.0运营标签与3.0标签的映射关系"""
        tags = TagMapOldTag.objects.using(settings.ZHENGXING_DB).filter(
            old_tag_id__in=cls.operation_tag1_ids
        ).values_list('tag_id', 'old_tag_id')
        tag_map_old_tag = defaultdict()
        for tag_id, old_tag_id in tags:
            if not tag_id or tag_id not in cls.operation_tag3_ids:
                continue
            tag_map_old_tag[old_tag_id] = tag_id
        return dict(tag_map_old_tag)

    @classmethod
    def get_operation_tag1_content_map(cls, operation_tag_ids):
        """1.0运营标签与内容关联关系"""
        tag_content_map = defaultdict(set)
        query = {"{}__in".format(cls.tag_name): list(operation_tag_ids)}
        fields = [cls.field, cls.tag_name]
        tags = cls.tag_model.objects.using(settings.SLAVE_DB_NAME).filter(**query).values_list(
            *fields
        )
        for content_id, tag_id in tags:
            tag_content_map[tag_id].add(content_id)
        return dict(tag_content_map)

    @classmethod
    def get_operation_tag3_content_map(cls, tag1_ids):
        """3.0运营标签与内容关联关系"""
        tag1_content_map = cls.get_operation_tag1_content_map(tag1_ids)
        if not tag1_content_map:
            return
        all_map = []
        tag3_ids = []
        for tag1_id in tag1_ids:
            tag3_id = cls.operation_tag3_map_tag1.get(tag1_id)
            content_ids = tag1_content_map.get(tag1_id)
            if not all([tag3_id, content_ids]): continue
            tag3_ids.append(tag3_id)
            all_map.extend([(tag3_id, content_id) for content_id in content_ids])
        fields = ['tag_v3_id', cls.field]
        tag3_content_map = set(cls.tag3_model.objects.using(settings.SLAVE_DB_NAME).filter(
            tag_v3_id__in=tag3_ids
        ).values_list(*fields))
        create_tag3_content_map = set(all_map) - tag3_content_map
        fields = [{cls.field: content_id, 'tag_v3_id': tag_id} for tag_id, content_id in create_tag3_content_map]
        cls.create_info.extend([cls.tag3_model(
            **item
        )for item in fields])

        return cls.create_info


class Command(BaseCommand):
    """python django_manage.py operation_tag_map --content_type="""
    def add_arguments(self, parser):
        parser.add_argument(
            '--content_type',
            help=u'内容类型(单选), choice is diary/topic/question/answer ...'
        )

    def handle(self, *args, **options):
        begin = time.time()
        content_type = options['content_type']
        if content_type not in CONTENT_TYPE_MAP:
            print("内容参数有误，请重新输入")
            return

        t = TagTool(content_type=content_type)
        operation_tag1_ids = list(t.operation_tag1_ids)
        tag3_model = t.tag3_model
        while operation_tag1_ids:
            if not operation_tag1_ids:
                break
            tag1_ids = operation_tag1_ids[:10]
            t.get_operation_tag3_content_map(tag1_ids)
            operation_tag1_ids = operation_tag1_ids[10:]

        create_info = t.create_info
        print('需要创建关联关系个数', len(create_info))
        while create_info:
            if not create_info:
                break
            tag3_model.objects.bulk_create(create_info[:2000])
            create_info = create_info[2000:]

        print('Done cost {}s'.format(int(time.time() - begin)))
