# -*- coding: UTF-8 -*-
import re
import json
from django.db.models import Q
from gm_dataquery.dataquery import DataBuilder, DataSQLQuery
from gm_dataquery.db import DB
from gm_types.user_hierarchy import CONSTELLATION

from mark.models.mark import MarkActivity, MarkFortuneConfigs, MarkActivityTag
from rpc.tool.protocol import gm_protocol
from api.models.face.skin_conf import SkinAge
from collections import defaultdict


def get_constellation_num_by_content(content):
    dic = {}
    for val, key in CONSTELLATION.choices:
        dic[key] = val
    return dic.get(content, 0)

class MarkActivityDB(DataBuilder):
    def getval_url(self, obj, need_escape=False):
        tag_ids = list(MarkActivityTag.objects.filter(mark_activity_id=obj.id).values_list('tag_id', flat=True))
        url = gm_protocol.daily_check(
            obj.id, tag_ids=tag_ids, name=obj.solid_title + obj.hollow_title, daily_check_type=obj.mark_type
        )
        return url

    def getval_title(self, obj, need_escape=False):
        return obj.solid_title + obj.hollow_title

    def getval_tag_id(self, obj, need_escape=False):
        tag_ids = MarkActivityTag.objects.filter(mark_activity_id=obj.id).values_list('tag_id', flat=True)
        if tag_ids:
            tag_id = tag_ids[0]
        else:
            tag_id = 0

        return tag_id


@DB
class MarkActivityDQ(DataSQLQuery):
    model = MarkActivity
    data_model = MarkActivityDB

    def create(self, **kwargs):
        tag_id = kwargs.pop('tag_id')
        obj = self.model.objects.create(**kwargs)
        MarkActivityTag.objects.create(
            mark_activity_id=obj.id,
            tag_id=tag_id,
        )
        kwargs['id'] = obj.id
        return kwargs

    def update(self, updates, **kwargs):
        id = kwargs.get("id", 0)
        if "tag_id" in updates:
            tag_id = updates.pop('tag_id')

            MarkActivityTag.objects.update_or_create(
                mark_activity_id=id,
                defaults={"tag_id": tag_id},
            )

        return super(MarkActivityDQ.sqlquery, self).update(updates, **kwargs)

    def filter_title(self, srch_key, srch_val, regex=False):
        return Q(solid_title__contains=srch_val) | Q(hollow_title__contains=srch_val)

    def filter_url(self, srch_key, srch_val, regex=False):
        res = re.search('.*?daily_check_id=(?P<id>\d+)', srch_val)
        if res:
            id = res.group('id')
        else:
            id = 0
        return Q(id=id)


class MarkFortuneConfigsDB(DataBuilder):
    def getval_skin_age(self, obj, need_escape=False):
        skin_ages = list(SkinAge.objects.filter(id=obj.skin_trait_id).values_list('content', flat=True))
        skin_age_content = skin_ages[0] if skin_ages else ''
        return skin_age_content

    def get_note_by_index(self, obj, i):

        res = ''
        notes = obj.notes
        if not notes:
            return res

        notes = json.loads(obj.notes)
        if len(notes) >= i + 1:
            res = notes[i]
        return res

    def getval_note_1(self, obj, need_escape=False):
        return self.get_note_by_index(obj, 0)

    def getval_note_2(self, obj, need_escape=False):
        return self.get_note_by_index(obj, 1)

    def getval_note_3(self, obj, need_escape=False):
        return self.get_note_by_index(obj, 2)

    def getval_note_4(self, obj, need_escape=False):
        return self.get_note_by_index(obj, 3)

    def getval_note_5(self, obj, need_escape=False):
        return self.get_note_by_index(obj, 4)

    def getval_note_6(self, obj, need_escape=False):
        return self.get_note_by_index(obj, 5)

    def get_fitting_or_dread_by_index(self, obj, i, is_fitting=True, is_content=True):
        res = ''
        fitting_and_dread = obj.fitting_and_dread
        if not fitting_and_dread:
            return res

        fitting_and_dread = json.loads(fitting_and_dread)
        if is_fitting:
            fitting_or_dread = fitting_and_dread.get('fitting', [])
        else:
            fitting_or_dread = fitting_and_dread.get('dread', [])

        if len(fitting_or_dread) >= i + 1:
            if is_content:
                res = fitting_or_dread[i].get('content', '')
            else:
                res = fitting_or_dread[i].get('icon', '')
        return res

    def getval_should_1_content(self, obj, need_escape=False):
        return self.get_fitting_or_dread_by_index(obj, 0)

    def getval_should_1_icon(self, obj, need_escape=False):
        return self.get_fitting_or_dread_by_index(obj, 0, is_content=False)

    def getval_should_2_content(self, obj, need_escape=False):
        return self.get_fitting_or_dread_by_index(obj, 1)

    def getval_should_2_icon(self, obj, need_escape=False):
        return self.get_fitting_or_dread_by_index(obj, 1, is_content=False)

    def getval_avoid_1_content(self, obj, need_escape=False):
        return self.get_fitting_or_dread_by_index(obj, 0, is_fitting=False)

    def getval_avoid_1_icon(self, obj, need_escape=False):
        return self.get_fitting_or_dread_by_index(obj, 0, is_fitting=False, is_content=False)

    def getval_avoid_2_content(self, obj, need_escape=False):
        return self.get_fitting_or_dread_by_index(obj, 1, is_fitting=False)

    def getval_avoid_2_icon(self, obj, need_escape=False):
        return self.get_fitting_or_dread_by_index(obj, 1, is_fitting=False, is_content=False)


@DB
class MarkFortuneConfigsDQ(DataSQLQuery):
    model = MarkFortuneConfigs
    data_model = MarkFortuneConfigsDB
    ERROR_MSG = u'同一海报内容，肤质对应的星座重复'

    def construct_fitting_or_dread(self, **kwargs):
        fitting_and_dread = defaultdict(list)
        for i in range(1, 3):
            fitting_item = {}
            dread_item = {}
            fitting_item['content'] = kwargs.pop('should_' + str(i) + '_content')
            fitting_item['icon'] = kwargs.pop('should_' + str(i) + '_icon')

            dread_item['content'] = kwargs.pop('avoid_' + str(i) + '_content')
            dread_item['icon'] = kwargs.pop('avoid_' + str(i) + '_icon')

            fitting_and_dread['fitting'].append(fitting_item)
            fitting_and_dread['dread'].append(dread_item)

        fitting_and_dread = json.dumps(dict(fitting_and_dread))
        return fitting_and_dread, kwargs

    def vaidate_constellation(self, constellation, mark_activity_id, skin_trait_id):
        constellations = list(self.model.objects.filter(
            mark_activity_id=mark_activity_id,
            skin_trait_id=skin_trait_id,
        ).values_list('constellation', flat=True))
        if constellation in constellations:
            return False
        return True

    def update_fitting_or_dread(self, fitting_and_dread, updates, fitting_or_dread, content_or_icon):
        for _index, value in updates:
            fitting_and_dread[fitting_or_dread][_index - 1][content_or_icon] = value

        return fitting_and_dread

    def create(self, **kwargs):
        res = {'msg': ''}
        mark_activity_id = kwargs.pop('mark_activity_id')
        skin_trait_id = kwargs.pop('skin_trait_id')
        constellation = kwargs.pop('constellation')

        if not self.vaidate_constellation(constellation, mark_activity_id, skin_trait_id):
            res['msg'] = self.ERROR_MSG
            return res

        obj = self.model(
            mark_activity_id=mark_activity_id,
            skin_trait_id=skin_trait_id,
            constellation=constellation,
        )
        notes = []
        for i in range(1, 7):
            note = kwargs.pop('note_' + str(i), '')
            if not note:
                continue
            notes.append(note)

        fitting_and_dread, kwargs = self.construct_fitting_or_dread(**kwargs)
        obj.notes = json.dumps(notes)
        obj.fitting_and_dread = fitting_and_dread
        for key, value in kwargs.items():
            setattr(obj, key, value)
        obj.save()
        res['id'] = obj.id
        return res

    def update(self, updates, **kwargs):
        res = {'msg': ''}
        id = kwargs.get('id', 0)
        obj = self.model.objects.get(id=id)

        note_contents = []
        fitting_contents = []
        fitting_icons = []
        dread_contents = []
        dread_icons = []

        # 星座校验（同一海报内，同一肌型对应的星座不能重复）
        constellation = updates.pop('constellation', '')
        if constellation and not self.vaidate_constellation(constellation, obj.mark_activity_id, obj.skin_trait_id):
            res['msg'] = self.ERROR_MSG
            return res

        for key, value in updates.items():
            if key.startswith('note'):
                note_contents.append((int(key.split('_')[1]), value))
            elif key.startswith('should') and key.endswith('content'):
                fitting_contents.append((int(key.split('_')[1]), value))
            elif key.startswith('should') and key.endswith('icon'):
                fitting_icons.append((int(key.split('_')[1]), value))
            elif key.startswith('avoid') and key.endswith('content'):
                dread_contents.append((int(key.split('_')[1]), value))
            elif key.startswith('avoid') and key.endswith('icon'):
                dread_icons.append((int(key.split('_')[1]), value))
            else:
                setattr(obj, key, value)
        notes = json.loads(obj.notes)
        for _index, note in note_contents:
            if len(notes) >= _index:
                notes[_index - 1] = note
            else:
                notes.append(note)
        notes = [note for note in notes if note]
        obj.notes = json.dumps(notes)

        fitting_and_dread = json.loads(obj.fitting_and_dread)
        fitting_and_dread = self.update_fitting_or_dread(fitting_and_dread, fitting_contents, 'fitting', 'content')
        fitting_and_dread = self.update_fitting_or_dread(fitting_and_dread, fitting_icons, 'fitting', 'icon')
        fitting_and_dread = self.update_fitting_or_dread(fitting_and_dread, dread_contents, 'dread', 'content')
        fitting_and_dread = self.update_fitting_or_dread(fitting_and_dread, dread_icons, 'dread', 'icon')

        obj.fitting_and_dread = json.dumps(fitting_and_dread)
        obj.save()

        return res

    def filter_skin_age(self, srch_key, srch_val, regex=False):
        skin_trait_ids = list(SkinAge.objects.filter(content__contains=srch_val).values_list('id', flat=True))
        return Q(skin_trait_id__in=skin_trait_ids)

    def filter_constellation(self, srch_key, srch_val, regex=False):
        constellation = get_constellation_num_by_content(srch_val)
        return Q(constellation=constellation)
