#!/usr/bin/env python
# -*- coding: utf-8 -*-

import asyncio
import time
import math
import random
from itertools import groupby, chain

from django.conf import settings
from django.core.management import BaseCommand

from gm_types.gaia import (
    TAG_V3_TYPE,
    TAG_TYPE_ATTR,
)

from tags.models.tag import (
    TagV3,
    AttrTag,
)
from qa.models import (
    AnswerAttrTagV3,
    AnswerTagV3,
)
from utils.common import big_qs_iter


class Command(BaseCommand):
    """
    kyc 创建的回答，attr_tag_id to tag_v3_id
    python django_manage.py sync_answer_attr_tag_to_v3_tag
    """
    rel_attr_tag_map_v3_tag = {}

    @staticmethod
    def get_tag_type_from_attr_type(attr_type):
        if attr_type == TAG_TYPE_ATTR.FIRST_SYMPTOM:
            return TAG_V3_TYPE.FIRST_SYMPTOM

        elif attr_type == TAG_TYPE_ATTR.SYMPTOM:
            return TAG_V3_TYPE.SECOND_SYMPTOM

        elif attr_type in (TAG_TYPE_ATTR.MODE, TAG_TYPE_ATTR.FIRST_BRAND):
            return TAG_V3_TYPE.FIRST_BRAND

        elif attr_type == TAG_TYPE_ATTR.BRAND:
            return TAG_V3_TYPE.SECOND_BRAND

        elif attr_type == TAG_TYPE_ATTR.MACROSCOPIC_MODE:
            return TAG_V3_TYPE.MACROSCOPIC_MODE

        elif attr_type == TAG_TYPE_ATTR.FIRST_APPEAL:
            return TAG_V3_TYPE.FIRST_APPEAL

        elif attr_type == TAG_TYPE_ATTR.SECOND_APPEAL:
            return TAG_V3_TYPE.SECOND_APPEAL

        elif attr_type == TAG_TYPE_ATTR.FIRST_POSITION:
            return TAG_V3_TYPE.FIRST_POSITION

        elif attr_type == TAG_TYPE_ATTR.POSITION:
            return TAG_V3_TYPE.SECOND_POSITION

        elif attr_type == TAG_TYPE_ATTR.DRUG:
            return TAG_V3_TYPE.DRUG

        elif attr_type == TAG_TYPE_ATTR.INSTRUMENT:
            return TAG_V3_TYPE.INSTRUMENT

        elif attr_type == TAG_TYPE_ATTR.CONSUMABLES:
            return TAG_V3_TYPE.CONSUMABLES

        elif attr_type == TAG_TYPE_ATTR.MATERIAL:
            return TAG_V3_TYPE.MATERIAL

        else:
            return None

    def _get_tag_from_attr(self, attr):
        tag_type = self.get_tag_type_from_attr_type(attr.aggregate_type)
        if not tag_type:
            return

        time.sleep(0.2 * random.random())

        _tag_obj = TagV3.objects.using(
            settings.ZHENGXING_DB
        ).filter(name=attr.name, tag_type=tag_type).only("id").first()
        if not _tag_obj:
            return

        self.rel_attr_tag_map_v3_tag.update({
            attr.id: _tag_obj.id
        })

        return "ok"

    @staticmethod
    def get_answer_rel_attr_tags():
        """
        获取回答关联的属性标签信息
        :return:
        """
        rel_attr_tag_infos = AnswerAttrTagV3.objects.using(
            settings.SLAVE_DB_NAME
        ).values_list("answer_id", "attr_tag_id").order_by("answer_id")

        rel_attr_infos = {}
        for _answer_id, items in groupby(big_qs_iter(rel_attr_tag_infos), key=lambda x: x[0]):
            rel_attr_infos[_answer_id] = [item[1] for item in items]

        return rel_attr_infos

    @staticmethod
    def get_answer_rel_tag_v3_ids(answer_ids):
        """
        获取回答关联的tag_v3_ids (这里是所有)
        :param answer_ids:
        :return:
        """
        rel_tag_v3_infos = AnswerTagV3.objects.using(
            settings.SLAVE_DB_NAME
        ).filter(answer_id__in=answer_ids).values_list("answer_id", "tag_v3_id")

        result = {}
        for answer_id, items in groupby(sorted(rel_tag_v3_infos, key=lambda item: item[0]), key=lambda item: item[0]):
            result[answer_id] = [item[1] for item in items]

        return result

    def get_attr_tag_map_tag_v3_infos(self, attr_tag_ids):
        """
        获取attr映射的tagv3信息
        :param attr_tag_ids:
        :return:
        """
        attr_tags_info_from_sql = AttrTag.objects.filter(
            pk__in=attr_tag_ids
        ).using(settings.ZHENGXING_DB).only("name", "aggregate_type", "id")

        tasks = []
        loop = asyncio.get_event_loop()
        for attr_obj in big_qs_iter(attr_tags_info_from_sql):
            future = loop.run_in_executor(None, self._get_tag_from_attr, attr_obj)
            tasks.append(future)

        # 学习下，看看是啥
        done, pending = loop.run_until_complete(asyncio.wait(tasks))

    def handle(self, *args, **options):
        """
        python django_manage.py sync_answer_attr_tag_to_v3_tag
        :param args:
        :param options:
        :return:
        """
        step = 100
        print("START")

        start_time = time.time()

        rel_attr_infos = self.get_answer_rel_attr_tags()
        self.get_attr_tag_map_tag_v3_infos(set(chain.from_iterable(rel_attr_infos.values())))
        answer_rel_tag_v3_infos = self.get_answer_rel_tag_v3_ids(list(rel_attr_infos.keys()))

        bulk_create_list = []
        bulk_create_nums = 0
        for answer_id, attr_ids in rel_attr_infos.items():

            has_rel_tag_v3_ids = answer_rel_tag_v3_infos.get(answer_id, [])

            for attr_id in attr_ids:
                tag_v3_id = self.rel_attr_tag_map_v3_tag.get(attr_id, 0)
                if not tag_v3_id or tag_v3_id in has_rel_tag_v3_ids:  # 这里做个已有查询。不做删除处理，仅新增
                    continue

                bulk_create_list.append(AnswerTagV3(
                    answer_id=answer_id,
                    tag_v3_id=tag_v3_id
                ))

            if len(bulk_create_list) >= step:
                print("bulk_create in loop")

                bulk_create_nums += len(bulk_create_list)
                AnswerTagV3.objects.bulk_create(bulk_create_list)

                bulk_create_list = []

        if bulk_create_list:
            print("bulk_create in end")

            bulk_create_nums += len(bulk_create_list)
            AnswerTagV3.objects.bulk_create(bulk_create_list)

        print('Done! cost {} s. bulk_create_nums {}'.format(time.time() - start_time, bulk_create_nums))
        print("END")
