# coding:utf-8
from datetime import datetime
from django.core.management.base import BaseCommand

from agile.models.tag import (
    TagMapTag, TagV3, AttrTag, AttrTagSynonym, TagSynonym, TagV3Relation, TagAttrRelation, TagV3MapAttrTag
)
from gm_types.gaia import TAG_V3_TYPE, TAG_TYPE_ATTR


class Command(BaseCommand):
    """
        属性转标签
    """
    @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

        else:
            return None

    def _get_tag_from_attr(self, attr):
        tag_type = self._get_tag_type_from_attr_type(attr.aggregate_type)
        return TagV3.objects.filter(name=attr.name, tag_type=tag_type).first()

    @staticmethod
    def _gets_attr(start, size=100):
        total = AttrTag.objects.filter().count()
        if start > total:
            return []
        return AttrTag.objects.filter()[start: start + size]

    def _create_tag_from_attrs(self, attrs):
        if not attrs:
            return
        insert_tag_dict = {}
        insert_tag_list = []
        for attr in attrs:
            tag_type = self._get_tag_type_from_attr_type(attr.aggregate_type)
            exist_tag = TagV3.objects.filter(name=attr.name, tag_type=tag_type).first()
            if exist_tag:
                continue
            if not attr.name:
                continue
            if insert_tag_dict.get(attr.name + str(tag_type)) is not None:
                continue
            insert_tag_list.append(TagV3(
                name=attr.name,
                homoionym=attr.homoionym,
                tag_type=tag_type,
                is_using_ai=attr.is_using_ai,
                is_display=False,
                is_online=attr.is_online,
            ))
            insert_tag_dict[attr.name + str(tag_type)] = 1
        if insert_tag_list:
            TagV3.objects.bulk_create(insert_tag_list)

    def _create_synonym_from_attrs(self, attrs):
        if not attrs:
            return
        attr_ids = [item.id for item in attrs]
        attr_synonym = AttrTagSynonym.objects.filter(tag_attr_id__in=attr_ids)
        if not attr_synonym:
            return
        attr_synonym_dict = {item.tag_attr_id: item.name for item in attr_synonym}
        insert_synonym_list = []
        for attr in attrs:
            tag_type = self._get_tag_type_from_attr_type(attr.aggregate_type)
            tag = TagV3.objects.filter(name=attr.name, tag_type=tag_type).first()
            if not tag:
                continue
            synonym = attr_synonym_dict.get(attr.id)
            if not synonym:
                continue
            insert_synonym_list.append(TagSynonym(
                name=synonym,
                tag_id=tag.id,
                tag_type=tag_type,
            ))
        if insert_synonym_list:
            TagSynonym.objects.bulk_create(insert_synonym_list)

    def _create_all_relation_from_attrs(self, attrs):
        # 标签全部创建完成后 才可以进行
        if not attrs:
            return
        attr_ids = [item.id for item in attrs]
        attr_dict = {item.id: item for item in attrs}
        relations = TagAttrRelation.objects.filter(parent_id__in=attr_ids)
        if not relations:
            return
        child_ids = [item.child_id for item in relations]
        child_attrs = AttrTag.objects.filter(id__in=child_ids)
        child_dict = {item.id: item for item in child_attrs}

        insert_relation_dict = {}
        insert_relation_list = []
        for relation in relations:
            parent_attr = attr_dict.get(relation.parent_id)
            child_attr = child_dict.get(relation.child_id)
            if not parent_attr or not child_attr:
                continue
            parent_tag = self._get_tag_from_attr(parent_attr)
            if not parent_tag:
                continue
            child_tag = self._get_tag_from_attr(child_attr)
            if not child_tag:
                continue
            exist_relation = TagV3Relation.objects.filter(parent_id=parent_tag.id, child_id=child_tag.id)
            if exist_relation:
                continue
            if insert_relation_dict.get(parent_tag.id):
                continue
            insert_relation_list.append(TagV3Relation(
                parent_id=parent_tag.id,
                child_id=child_tag.id,
            ))
            insert_relation_dict[parent_tag.id] = child_tag.id
        if insert_relation_list:
            TagV3Relation.objects.bulk_create(insert_relation_list)

    @staticmethod
    def _get_time_string(time):
        return time.strftime('%Y-%m-%d %H:%M:%S %f')

    def _update_tag_map(self, attr_tag_maps):
        attr_ids = [item.tag_attr_id for item in attr_tag_maps]
        attr_tag_map_dict = {item.tag_attr_id: item for item in attr_tag_maps}
        attrs = AttrTag.objects.filter(id__in=attr_ids)
        if not attrs:
            return
        for attr in attrs:
            tag = self._get_tag_from_attr(attr)
            attr_tag_map = attr_tag_map_dict.get(attr.id)
            if not tag or not attr_tag_map:
                continue
            # 此处更新 会影响该model使用，需要调整此model数据使用地方的数据获取，tag_attr_id不再获取AttrTag，获取TagV3
            TagV3MapAttrTag.objects.filter(tag_attr_id=attr_tag_map.tag_attr_id).update(tag_attr_id=tag.id)

    def update_all_tag_map(self, size=100):
        print 'start update_all_tag_map at {}'.format(self._get_time_string(datetime.now()))
        qs = TagV3MapAttrTag.objects.filter()
        start = 0
        end = size
        attr_tag_maps = qs[start: end]
        while attr_tag_maps:
            print 'update_all_tag_map dealing start is {} end is {} at {}'.format(
                start, end, self._get_time_string(datetime.now()))
            self._update_tag_map(attr_tag_maps)
            start = end
            end = end + size
            attr_tag_maps = qs[start: end]

        print 'end update_all_tag_map at {}'.format(self._get_time_string(datetime.now()))

    def attr_to_tag_create(self):
        print 'start attr_to_tag_create at {}'.format(self._get_time_string(datetime.now()))
        start = 0
        size = 100
        attrs = self._gets_attr(start, size)
        while attrs:
            print 'attr_to_tag_create dealing start is {} at {}'.format(
                start, self._get_time_string(datetime.now()))
            self._create_tag_from_attrs(attrs)
            self._create_synonym_from_attrs(attrs)

            start = start + size
            attrs = self._gets_attr(start, size)

        print 'end attr_to_tag_create at {}'.format(self._get_time_string(datetime.now()))

    def attr_relation_create(self):
        print 'start attr_relation_create at {}'.format(self._get_time_string(datetime.now()))
        start = 0
        size = 100
        attrs = self._gets_attr(start, size)
        while attrs:
            print 'attr_relation_create dealing start is {} at {}'.format(
                start, self._get_time_string(datetime.now()))
            self._create_all_relation_from_attrs(attrs)

            start = start + size
            attrs = self._gets_attr(start, size)

        print 'end attr_relation_create at {}'.format(self._get_time_string(datetime.now()))

    def handle(self, *args, **options):
        print 'start deal at {}'.format(self._get_time_string(datetime.now()))
        # 属性迁移为标签
        self.attr_to_tag_create()
        # 属性关联关系迁移
        self.attr_relation_create()
        # 标签与属性关联关系更新
        self.update_all_tag_map()
        print 'end deal at {}'.format(self._get_time_string(datetime.now()))
