# coding:utf-8
import json
import math
import random
import logging
import traceback
from libs.cache import redis_client
from django.conf import settings
from libs.error import logging_exception
from libs.es import es_query, get_highlight_query_analyzer
from gm_rpcd.all import bind
from gm_types.doris import CARD_TYPE
from gm_types.gaia import (
    DIARY_ORDER_TYPE,
    QUESTION_ORDER_TYPE,
    TAB_TYPES_NEW
)
from gm_types.doris import ANSWER_SORT_TYPE
from search.utils.recommend import DeviceRecommend, DeviceRecommendRead
from search.views.diary import get_diaries
from search.views.question import search_question
from search.views.answer import filter_answer
from libs.algorithms import variousness, region_division

import pdb


def get_device_unread(device_id, tab_type, feed_type, city_id, offset, size,
                      filters={}, sort_type=QUESTION_ORDER_TYPE.DEFAULT,
                      answer_sort_type=ANSWER_SORT_TYPE.DEFAULT):
    # 获取推荐id列表
    segment_size = 200
    offset = math.floor(offset / segment_size) * segment_size
    recommends = DeviceRecommend.load(tab_type, feed_type, city_id, offset)
    if not recommends:

        # 获取问题id
        if feed_type == CARD_TYPE.QUESTION:
            questions_ids = search_question(
                query='', offset=offset, size=segment_size, filters=filters, sort_type=sort_type
            )
            recommends = questions_ids["question_ids"]

        # 获取回答id
        elif feed_type == CARD_TYPE.ANSWER:
            questions_ids = filter_answer(
                query='', offset=offset, size=segment_size, filters=filters, sort_type=answer_sort_type)
            recommends = questions_ids["answer_ids"]

            if tab_type != TAB_TYPES_NEW.HOME_VIDEO:
                random.shuffle(recommends)

        elif feed_type == CARD_TYPE.DIARY:
            diaries_ids = get_diaries(
                offset=offset, size=segment_size, filters=filters,
                user_city_tag_id=city_id, sort_type=DIARY_ORDER_TYPE.FEED
            )
            recommends = diaries_ids["diaries_ids"]

        DeviceRecommend.store(tab_type, feed_type, city_id, offset, recommends, ex=2 * 60)

    # 获取该设备已经读取的推荐id列表
    read = DeviceRecommendRead.load(device_id, tab_type, feed_type, city_id, offset)

    # 差集得到未读id列表，并且更新已读
    ret = list(set(recommends) - set(read)) if set(recommends) - set(read) else []
    ret.sort(key=recommends.index)  # 保证顺序
    ret = ret[:size]
    v = list(set(read) | set(ret)) if ret else []  # 没有未读则无需更新
    v.sort(key=(read + ret).index)  # 保证顺序
    if v:
        DeviceRecommendRead.store(device_id, tab_type, feed_type, city_id, offset, v, ex=1 * 60 * 60)
    else:
        # 没有未读设置过期
        DeviceRecommendRead.store(device_id, tab_type, feed_type, city_id, offset, recommends[:size], ex=1 * 60 * 60)

    return ret if ret else recommends[:size]


@bind("doris/recommend/home_feed")
def get_home_feed_recommend(device_id, tab_type, feed_type, offset, size, city_id, **kwargs):
    """获取首页feed推荐的id列表。

    kwargs: city_id / filters / query
    """
    filters = kwargs.get("filters", {})
    sort_type = kwargs.get("sort_type", QUESTION_ORDER_TYPE.DEFAULT)
    answer_sort_type = kwargs.get("answer_sort_type", ANSWER_SORT_TYPE.DEFAULT)
    res = get_device_unread(device_id, tab_type, feed_type, city_id, offset, size, filters, sort_type, answer_sort_type)

    return {feed_type: res}


@bind("doris/recommend/video_tab")
def get_video_tab_recommend(card_type, offset, size, device_id, source_type, **kwargs):
    try:
        logging.info("get redis_client:%s" % redis_client)
        return RecommendFeed.dispatch(card_type, offset, size, device_id, source_type)
    except:
        logging_exception()
        return {card_type: []}


def scatter(data, size):
    for item in data:
        item['id'] = item['_id']
        item['group'] = item.get('_source', {}).get('user_id',None)
    data = variousness(data, size)
    return data[:size]

def scatter_diary(data, size):
    for item in data:
        item['id'] = item['_id']
        item['group'] = item.get('_source', {}).get('user',{}).get('id',None)
    data = variousness(data, size)
    return data[:size]

class RecommendFeed:
    @classmethod
    def dispatch(cls, card_type, offset, size, device_id, source_type):
        data = []
        if card_type == CARD_TYPE.QA:
            data = cls.answer_sort(offset=offset, size=size, device_id=device_id, source_type=source_type)
            data = list(map(int, data))
        elif card_type == CARD_TYPE.DIARY:
            data = cls.diary_sort(offset=offset, size=size, device_id=device_id, source_type=source_type)
            data = list(map(int, data))
        elif card_type == CARD_TYPE.USERTOPIC:
            data = cls.user_tractate_sort(offset=offset, size=size, device_id=device_id, source_type=source_type)
            data = list(map(int, data))
        elif card_type == CARD_TYPE.DOCTORTOPIC:
            data = cls.doctor_tractate_sort(offset=offset, size=size, device_id=device_id, source_type=source_type)
            data = list(map(int, data))
        elif card_type == CARD_TYPE.ENCYCLOPEDIA:
            data = cls.wiki_sort(offset=offset, size=size, source_type=source_type)

        return {card_type: data}

    @staticmethod
    def user_tractate_sort(filters=None, offset=0, size=10, query=None, device_id="", source_type=-1):
        try:
            redis_key = ""
            have_read_answer_id_list_redis = []
            if not isinstance(device_id, str):
                device_id = ""
            if source_type == 1:
                if device_id:
                    redis_key = "doris_feed:home_video_tractate" + ":device_id:" + str(device_id)
                    redis_question_val_list = redis_client.get(redis_key)
                    # 获取已读video_tractate
                    if redis_question_val_list:
                        have_read_answer_id_list_redis = list(json.loads(redis_question_val_list))
                        logging.info("get redis_question_val_list:%s" % redis_question_val_list)

            filters = filters or {}
            tag_ids = []
            for k, v in filters.items():
                if k == "tag_ids":
                    tag_ids = v
            q = {}
            q["query"] = {
                "bool": {
                    "must": [
                        {"term": {"is_online": True}},
                        {"term": {"is_video": True}},
                    ],
                    "must_not": {
                        "terms": {
                            "id": have_read_answer_id_list_redis
                        }
                    }
                }
            }
            q["sort"] = [{"tractate_score": {"order": "desc"}}, {"post_time": {"order": "desc"}}]
            tractate_id_list = []
            logging.info('test query es :%s' % str(q).encode('utf-8'))
            res = es_query('tractate', q, offset, 100)
            hits = res["hits"]
            hits["hits"] = scatter(hits['hits'], size)
            for item in hits["hits"]:
                if '_source' in item:
                    id = item['_source']['id']
                    tractate_id_list.append(id)
                    have_read_answer_id_list_redis.append(id)

            if source_type == 1:
                if len(tractate_id_list) == 0:
                    if len(have_read_answer_id_list_redis) >= size:
                        redis_client.delete(redis_key)
                        redis_client.set(redis_key, json.dumps(have_read_answer_id_list_redis[0:size]))
                        redis_client.expire(redis_key, 60 * 60 * 24 * 15)
                        tractate_id_list = have_read_answer_id_list_redis[0:size]

                    else:
                        redis_client.set(redis_key, json.dumps(have_read_answer_id_list_redis))
                        redis_client.expire(redis_key, 60 * 60 * 24 * 15)
                        tractate_id_list = have_read_answer_id_list_redis
                else:
                    """
                        保存已读的问答数据
                    """
                    if redis_key:
                        redis_client.set(redis_key, json.dumps(have_read_answer_id_list_redis))
                        redis_client.expire(redis_key, 60 * 60 * 24 * 15)
            return tractate_id_list

        except:

            logging.error("catch exception,logins:%s" % traceback.format_exc())

            return []

    @staticmethod
    def wiki_sort(filters=None, offset=0, size=10, query=None, source_type=-1):
        try:
            filters = filters or {}
            tag_ids = []
            for k, v in filters.items():
                if k == "tag_ids":
                    tag_ids = v
            q = {}
            q["query"] = {
                "bool": {
                    "must": [
                        {"term": {"is_online": True}},
                        {"term": {"is_video": True}}
                    ]
                }
            }
            q["sort"] = {"create_time": {"order": "desc"}}
            wiki_id_dict = list()
            logging.info('test query es :%s' % str(q).encode('utf-8'))
            res = es_query('newwiki', q, offset, size)
            res_hit = res["hits"]["hits"]
            for item in res_hit:
                if '_source' in item:
                    id = item['_source']['id']
                    type_id = item['_source']['wikitype']
                    wiki_id_dict.append({"type": type_id, "id": id})
            return wiki_id_dict

        except:

            logging.error("catch exception,logins:%s" % traceback.format_exc())
            Dict = dict()
            return Dict

    @staticmethod
    def answer_sort(filters=None, offset=0, size=10, device_id="", source_type=-1):
        try:
            redis_key = ""
            have_read_answer_id_list_redis = []
            if not isinstance(device_id, str):
                device_id = ""
            if source_type == 1:
                if device_id:
                    redis_key = "doris_feed:home_video_answer" + ":device_id:" + str(device_id)
                    redis_question_val_list = redis_client.get(redis_key)
                    # 获取已读video_tractate
                    if redis_question_val_list:
                        have_read_answer_id_list_redis = list(json.loads(redis_question_val_list))

            filters = filters or {}
            tag_ids = []
            for k, v in filters.items():
                if k == "tag_ids":
                    tag_ids = v
            q = {}
            q["query"] = {
                "bool": {
                    "must": [
                        {"term": {"is_online": True}},
                        {"term": {"content_type": 1}}
                    ],
                    "must_not": {
                        "terms": {
                            "id": have_read_answer_id_list_redis
                        }
                    }
                }

            }
            q["sort"] = {"create_time": {"order": "desc"}}
            answer_id_list = []
            logging.info('test query es :%s' % str(q).encode('utf-8'))
            res = es_query('answer', q, offset, 100)
            hits = res["hits"]
            hits["hits"] = scatter(hits['hits'], size)
            for item in hits["hits"]:
                if '_source' in item:
                    id = item['_source']['id']
                    answer_id_list.append(id)
                    have_read_answer_id_list_redis.append(id)

            if source_type == 1:
                if len(answer_id_list) == 0:
                    if len(have_read_answer_id_list_redis) >= size:
                        redis_client.delete(redis_key)
                        redis_client.set(redis_key, json.dumps(have_read_answer_id_list_redis[0:size]))
                        redis_client.expire(redis_key, 60 * 60 * 24 * 15)
                        answer_id_list = have_read_answer_id_list_redis[0:size]

                    else:
                        redis_client.set(redis_key, json.dumps(have_read_answer_id_list_redis))
                        redis_client.expire(redis_key, 60 * 60 * 24 * 15)
                        answer_id_list = have_read_answer_id_list_redis
                else:
                    """
                        保存已读的问答数据
                    """
                    if redis_key:
                        redis_client.set(redis_key, json.dumps(have_read_answer_id_list_redis))
                        redis_client.expire(redis_key, 60 * 60 * 24 * 15)

            return answer_id_list

        except:

            logging.error("catch exception,logins:%s" % traceback.format_exc())

            return []

    @staticmethod
    def doctor_tractate_sort(filters=None, offset=0, size=10, query=None, device_id="", source_type=-1):
        try:
            redis_key = ""
            have_read_answer_id_list_redis = []
            if not isinstance(device_id, str):
                device_id = ""

            if device_id:
                redis_key = "doris_feed:home_video_doctor_tractate" + ":device_id:" + str(device_id)
                redis_question_val_list = redis_client.get(redis_key)
                # 获取已读video_tractate
                if redis_question_val_list:
                    have_read_answer_id_list_redis = list(json.loads(redis_question_val_list))
                    logging.info("get redis_question_val_list:%s" % redis_question_val_list)

            filters = filters or {}
            tag_ids = []
            for k, v in filters.items():
                if k == "tag_ids":
                    tag_ids = v
            q = {}

            q["query"] = {
                "bool": {
                    "must": [
                        {"term": {"is_online": True}},
                        {"term": {"is_video": True}}
                    ],
                    "must_not": {
                        "terms": {
                            "id": have_read_answer_id_list_redis
                        }
                    }
                }
            }
            q["sort"] = [{"tractate_score": {"order": "desc"}}, {"post_time": {"order": "desc"}}]
            tractate_id_list = []
            logging.info('test query es :%s' % str(q).encode('utf-8'))
            res = es_query('tractate', q, offset, size)
            res_hit = res["hits"]["hits"]
            for item in res_hit:
                if '_source' in item:
                    id = item['_source']['id']
                    tractate_id_list.append(id)
                    have_read_answer_id_list_redis.append(id)

            if len(tractate_id_list) == 0:
                if len(have_read_answer_id_list_redis) >= size:
                    redis_client.delete(redis_key)
                    redis_client.set(redis_key, json.dumps(have_read_answer_id_list_redis[0:size]))
                    redis_client.expire(redis_key, 60 * 60 * 24 * 15)
                    tractate_id_list = have_read_answer_id_list_redis[0:size]

                else:
                    redis_client.set(redis_key, json.dumps(have_read_answer_id_list_redis))
                    redis_client.expire(redis_key, 60 * 60 * 24 * 15)
                    tractate_id_list = have_read_answer_id_list_redis
            else:
                """
                    保存已读的问答数据
                """
                if redis_key:
                    redis_client.set(redis_key, json.dumps(have_read_answer_id_list_redis))
                    redis_client.expire(redis_key, 60 * 60 * 24 * 15)

            return tractate_id_list

        except:

            logging.error("catch exception,logins:%s" % traceback.format_exc())

            return []

    @staticmethod
    def diary_sort(filters=None, offset=0, size=10, query=None, device_id="", source_type=-1):
        try:
            redis_key = ""
            have_read_answer_id_list_redis = []
            if not isinstance(device_id, str):
                device_id = ""

            if source_type == 1:
                if device_id:
                    redis_key = "doris_feed:home_video_diary" + ":device_id:" + str(device_id)
                    redis_question_val_list = redis_client.get(redis_key)
                    # 获取已读video_tractate
                    if redis_question_val_list:
                        have_read_answer_id_list_redis = list(json.loads(redis_question_val_list))
                        logging.info("get redis_question_val_list:%s" % redis_question_val_list)

            filters = filters or {}
            tag_ids = []
            for k, v in filters.items():
                if k == "tag_ids":
                    tag_ids = v
            q = {}
            q["query"] = {
                "bool": {
                    "must": [
                        {"term": {"is_online": True}},
                        {"term": {"has_video_cover": True}},
                        {"range": {"content_level": {"gte": 3, "lte": 5}}}
                    ],
                    "must_not": {
                        "terms": {
                            "id": have_read_answer_id_list_redis
                        }
                    }
                }
            }
            q["sort"] = [{'is_sink': {'order': 'asc'}},
                         {'_script':
                              {'lang': settings.ES_SCRIPT_LANG,
                               'script_file': 'sort_diary-sink-by-org',
                               'type': 'number',
                               'order': 'desc'}},
                         {'content_level': {'order': 'desc'}},
                         {'last_update_time': {'order': 'desc'}}]

            diary_id_list = []
            logging.info('test query es :%s' % str(q).encode('utf-8'))
            res = es_query('diary', q, offset, 100)
            hits = res["hits"]
            hits["hits"] = scatter_diary(hits['hits'], size)
            for item in hits["hits"]:
                if '_source' in item:
                    id = item['_source']['id']
                    diary_id_list.append(id)
                    have_read_answer_id_list_redis.append(id)

            if source_type == 1:
                if len(diary_id_list) == 0:
                    if len(have_read_answer_id_list_redis) >= size:
                        redis_client.delete(redis_key)
                        redis_client.set(redis_key, json.dumps(have_read_answer_id_list_redis[0:size]))
                        redis_client.expire(redis_key, 60 * 60 * 24 * 15)
                        diary_id_list = have_read_answer_id_list_redis[0:size]

                    else:
                        redis_client.set(redis_key, json.dumps(have_read_answer_id_list_redis))
                        redis_client.expire(redis_key, 60 * 60 * 24 * 15)
                        diary_id_list = have_read_answer_id_list_redis
                else:
                    """
                        保存已读的问答数据
                    """
                    if redis_key:
                        redis_client.set(redis_key, json.dumps(have_read_answer_id_list_redis))
                        redis_client.expire(redis_key, 60 * 60 * 24 * 15)

            return diary_id_list

        except:

            logging.error("catch exception,logins:%s" % traceback.format_exc())

            return []
