# coding=utf8
from __future__ import unicode_literals, absolute_import, print_function
import logging
import traceback
import json
from libs.cache import redis_client
from trans2es.models.query_word_conversion import TagConversion, DoctorConversion, HospitalConversion
from trans2es.models.strategy_search_word import StrategyHistoryQueryWords
from libs.cache import redis_client
import base64
from gm_types.doris import MIND_TYPE
from gm_rpcd.all import bind

QUERY_KEY = "query:{}:set"

LABEL_VALUE = {
    MIND_TYPE.PROJECT: 8,
    MIND_TYPE.HOSPITAL: 7,
    MIND_TYPE.DOCTOR: 6,
    MIND_TYPE.FREE_FACE: 4,
    MIND_TYPE.FACE: 3,
    MIND_TYPE.AREA: 2,
    MIND_TYPE.USER: 1,
    MIND_TYPE.UNKNOWN: 0
}

QUERY_WORD_LABEL_NEED_MODIFIED = {
    u"玻尿酸": MIND_TYPE.PROJECT,
    u"鼻": MIND_TYPE.PROJECT,
    u"眼": MIND_TYPE.PROJECT,
    u"嘴": MIND_TYPE.PROJECT,
    u"脱毛": MIND_TYPE.PROJECT
}


class TagTab(object):
    Weight = {
        'search': 0.4,
        'trans': 0.6
    }

    SearchScore = {
        0.7: 100,
        0.1: 80,
        0.05: 60,
        0.01: 40,
        0: 20,
    }

    TransScore = {
        0.7: 100,
        0.5: 80,
        0.3: 60,
        0.1: 40,
        0: 20
    }

    def cal_score(self, search_rate, conversion_rate):
        s1 = self._cal_score(search_rate, 'SearchScore') * self.Weight['search']
        s2 = self._cal_score(conversion_rate, 'TransScore') * self.Weight['trans']
        return s1 + s2

    def _cal_score(self, item, type_):
        item *= 100.0
        scoreweight = getattr(self, type_)
        for k in sorted(scoreweight.keys(), reverse=True):
            if item >= k:
                return scoreweight[k]


class DocTab(TagTab):
    SearchScore = {
        0.04: 100,
        0.01: 80,
        0.001: 60,
        0.0002: 40,
        0: 20,
    }

    TransScore = {
        0.47: 100,
        0.2: 80,
        0.1: 60,
        0.01: 40,
        0: 20
    }


class HosTab(TagTab):
    SearchScore = {
        0.47: 100,
        0.2: 80,
        0.1: 60,
        0.01: 40,
        0: 20
    }

    TransScore = {
        1: 100,
        0.45: 90,
        0.27: 80,
        0.21: 70,
        0.15: 60,
        0.12: 50,
        0.09: 40,
        0.06: 30,
        0.04: 20,
        0: 10,
    }


class QueryWordAttr(object):
    # 获取TagConversion表最新的日期
    tag_latest_date = None
    doctor_latest_date = None
    hospital_latest_date = None

    tips_num_redis_key_prefix = "search_tips:tips_mapping_num"

    tagtab = TagTab()
    doctab = DocTab()
    hostab = HosTab()

    @classmethod
    def get_hot_search_query_word_weight(cls, name):
        try:
            search_info = StrategyHistoryQueryWords.objects.filter(keyword=name).first()
            weight = int(0.0001 * search_info.search_num)
            return weight
        except:
            logging.error("catch exception,err_msg:%s" % traceback.format_exc())
            return 0.0

    @classmethod
    def get_hot_search_query_word_weight_v1(cls, name):
        try:
            search_num = StrategyHistoryQueryWords.objects.filter(keyword=name).values_list(
                "search_num", flat=True).first()
            if not search_num:
                search_num = 0

            return search_num * 0.01
        except:
            logging.error("catch exception,err_msg:%s" % traceback.format_exc())
            return 0.0

    @classmethod
    def get_project_query_word_weight(cls, name):
        try:
            if not cls.tag_latest_date:
                cls.tag_latest_date = TagConversion.objects.latest('update_date').update_date

            tag_query_results = TagConversion.objects.filter(query=name, update_date=cls.tag_latest_date)

            total_score = 0.0
            for query_item in tag_query_results:
                item_score = cls.tagtab.cal_score(query_item.search_rate, query_item.conversion_rate)
                total_score += item_score

            return total_score
        except:
            logging.error("catch exception,err_msg:%s" % traceback.format_exc())
            return 0.0

    @classmethod
    def get_doctor_query_word_weight(cls, name=None, doctor_id=None):
        try:
            if not cls.doctor_latest_date:
                cls.doctor_latest_date = DoctorConversion.objects.latest('update_date').update_date

            doc_query_results = DoctorConversion.objects.filter(business_id=doctor_id,
                                                                update_date=cls.doctor_latest_date)

            total_score = 0.0
            for query_item in doc_query_results:
                item_score = cls.doctab.cal_score(query_item.search_rate, query_item.conversion_rate)
                total_score += item_score

            return total_score
        except:
            logging.error("catch exception,err_msg:%s" % traceback.format_exc())
            return 0.0

    @classmethod
    def get_hospital_query_word_weight(cls, name=None, hospital_id=None):
        try:
            if not cls.hospital_latest_date:
                cls.hospital_latest_date = HospitalConversion.objects.latest('update_date').update_date

            hospital_query_results = HospitalConversion.objects.filter(business_id=hospital_id,
                                                                       update_date=cls.hospital_latest_date)

            total_score = 0.0
            for query_item in hospital_query_results:
                item_score = cls.hostab.cal_score(query_item.search_rate, query_item.conversion_rate)
                total_score += item_score

            return total_score
        except:
            logging.error("catch exception,err_msg:%s" % traceback.format_exc())
            return 0.0

    @classmethod
    def get_query_results_num(cls, name):
        try:
            redis_data = redis_client.hget(cls.tips_num_redis_key_prefix, name)
            redis_val_dict = json.loads(str(redis_data, encoding="utf-8")) if redis_data else {}
            results_num = redis_val_dict['t'] if 't' in redis_val_dict else 0

            return results_num
        except:
            logging.error("catch exception,err_msg:%s" % traceback.format_exc())
            return 0

    @classmethod
    def get_search_query_results_num(cls, name):
        try:
            total_num = 0
            data = StrategyHistoryQueryWords.objects.filter(keyword=name).values("answer_num", "tractate_num",
                                                                                 "diary_num").first()

            if data:
                for value in data.values():
                    total_num += value

            return total_num
        except:
            logging.error("catch exception,err_msg:%s" % traceback.format_exc())
            return 0

    @classmethod
    def save_query_to_redis(cls, query, type_v1=False):
        try:
            return True
            # lower_query = str(query).lower()
            # key = "save_sub_query_to_redis"
            # if type_v1:
            #     key = "save_sub_query_to_redis_v1"
            # redis_data = redis_client.get(key)
            # if redis_data:
            #     redis_data = json.loads(str(redis_data, encoding="utf8"))
            #     if lower_query in redis_data:
            #         return False
            #     else:
            #         redis_data.append(lower_query)
            #         redis_client.set(key, json.dumps(redis_data))
            #         return True
            # else:
            #     redis_client.set(key, json.dumps([lower_query]))
            #     return True
            # if from_type == "search_query":
            #     order_weight = cls.get_hot_search_query_word_weight(name=query)
            #     search_num = cls.get_search_query_results_num(name=query)
            # else:
            #     order_weight = cls.get_project_query_word_weight(name=query)
            #     search_num = cls.get_query_results_num(name=query)

            # if redis_data:
            #     json_data = json.loads(redis_data)
            #     have_save_order_weight = json_data.get('order_weight', 0)
            #     have_save_search_num = json_data.get('order_weight', 0)
            #
            #     logging.info(
            #         "query:%s,have_save_order_weight:%s,have_save_search_num:%s,order_weight:%s,search_num:%s" % (
            #             query, have_save_order_weight, have_save_search_num, order_weight, search_num))
            #
            #     if get_ret:
            #         if have_save_order_weight >= order_weight and have_save_search_num == search_num:
            #             return True
            #         else:
            #             return False
            #     else:
            #         if have_save_order_weight < order_weight or (
            #                 have_save_order_weight == order_weight and have_save_search_num < search_num):
            #             logging.info(
            #                 "query:%s,have_save_order_weight:%s,have_save_search_num:%s,order_weight:%s,search_num:%s" % (
            #                     query, have_save_order_weight, have_save_search_num, order_weight, search_num))
            #
            #             redis_client.hset(key, lower_query,
            #                               json.dumps({"order_weight": order_weight, "search_num": search_num}))
            #         else:
            #             pass
            # elif get_ret == False:
            #     redis_client.hset(key, lower_query,
            #                       json.dumps({"order_weight": order_weight, "search_num": search_num}))
        except:
            logging.error("catch exception,err_msg:%s" % traceback.format_exc())
            return False


def label_key(label):
    return LABEL_VALUE.get(label)


def get_tips_word_type(query=''):
    query_base64 = base64.b64encode(query.encode('utf8')).decode('utf8')
    key = QUERY_KEY.format(query_base64)
    labels = list(map(lambda x: x.decode("utf8"), list(redis_client.smembers(key))))
    labels.append(MIND_TYPE.UNKNOWN)
    if query in QUERY_WORD_LABEL_NEED_MODIFIED:
        labels.append(MIND_TYPE.PROJECT)
    labels.sort(key=label_key, reverse=True)
    return labels[0]
