from gm_types.gaia import DIARY_ORDER_TYPE
from gm_types.doris import ANSWER_SORT_TYPE
from gm_types.doris import ARTICLE_SORT_TYPE
from gm_types.mimas import CONTENT_CLASS
from gm_rpcd.all import bind
from search.utils.diary import recall_diary
from search.utils.answer import recall_answers
from search.utils.article import recall_articles
from libs.cache import redis_client
from libs.error import logging_exception
from extend.models.gaia import City
from search.views.tractate import tractate_sort
from search.utils.service import recommed_service_category_device_id, recommed_service_category_device_id_v2
import logging
import json
from django.conf import settings
import traceback
from libs.es import es_index_adapt
from libs.es import es_msearch, es_query
from gm_types.doris import CARD_TYPE
from search.views.relation_search import Tag
from gm_types.gaia import TAG_TYPE

MAX_LOAD = 200
logger = logging.getLogger(__name__)


@bind("doris/recommend/content_detail_tag")
def content_detail_tag(tag={}, page=1, city_id=None, city_tag_id=-1,
                       device_id=None, card_type="diary", card_id=-1):
    """
    日记帖子问答专栏的详情页统一为一个接口
    :param tag:
    :param page:
    :param city_id:
    :param city_tag_id:
    :param device_id:
    :param card_type:
    :param card_id:
    :return:
    """
    try:
        all_tags = list()
        new_all_tags = list()
        diary_sort_params = {}
        tractate_filters = {}
        article_filters = {}
        question_filters = {}
        diary_results_list = list()
        question_results_list = list()
        tractate_results_list = list()
        article_results_list = list()
        sort_params = {}
        have_read_diary = list()
        have_read_article = list()
        have_read_tractate = list()
        have_read_question = list()
        have_click_article = list()
        have_click_question = list()
        have_click_diary = list()
        have_click_tractate = list()
        tag_names = []
        noarea_tags = []
        ####拿到当前卡片的所有标签
        tag_query = {
            "query": {
                "term": {
                    "id": card_id
                }
            }
        }

        if card_type == "question":
            tag_query = {
                "query": {
                    "term": {
                        "question_id": card_id
                    }
                }
            }

        index_type = {"diary": "diary", "usertopic": "tractate", "answer": "answer", "article": "article", "question": "answer"}
        index_tag_name = {"diary": "closure_tag_ids", "usertopic": "tractate_tag_list", "answer": "tag_ids",
                          "article": "tag_ids", "question": "tag_ids"}

        fresh_tractate_tag_name = list()
        content_star_keyword = []
        content_keyword = []
        res = es_query(index_type.get(card_type, "diary"), tag_query, offset=0, size=1)
        if res["hits"]["total"] > 0:
            ret_hits = res["hits"]["hits"]
            for item in ret_hits:
                name = index_tag_name.get(card_type, "tags")
                tag_names = item["_source"][name]
                if card_type == "usertopic":
                    fresh_tractate_tag_name = item["_source"]["fresh_tractate_tag_name"] if "fresh_tractate_tag_name" in \
                                                                                            item["_source"] else []
                content_star_keyword = item["_source"]["content_star_keyword"] if "content_star_keyword" in item["_source"] else []
                content_keyword = item["_source"]["content_keyword"] if "content_keyword" in item["_source"] else []

        if len(tag_names) > 0:
            noarea_tags = list(
                Tag.objects.filter(id__in=tag_names).exclude(tag_type=TAG_TYPE.CITY).values_list("name", flat=True))

        if card_type == "usertopic":
            noarea_tags.extend(fresh_tractate_tag_name)

        ###
        redis_key = "doris:content_detail_commend:have_read_list:" + device_id
        if page != 1:
            have_read_dict = redis_client.get(redis_key)
            if have_read_dict and len(have_read_dict) > 0:
                have_read_dict = json.loads(have_read_dict.decode('utf-8'))
                have_read_article = have_read_dict.get("have_read_article", [])
                have_read_question = have_read_dict.get("have_read_question", [])
                have_read_diary = have_read_dict.get("have_read_diary", [])
                have_read_tractate = have_read_dict.get("have_read_tractate", [])

        ###过滤今天用户点击过的卡片ID

        have_click_data_key = "doris:content_detail_commend:have_click_list:" + device_id
        have_click_dict = redis_client.get(have_click_data_key)
        if have_click_dict and len(have_click_dict) > 0:
            have_click_dict = json.loads(have_click_dict.decode('utf-8'))
            have_click_article = have_click_dict.get("have_click_article", [])
            have_click_question = have_click_dict.get("have_click_question", [])
            have_click_diary = have_click_dict.get("have_click_diary", [])
            have_click_tractate = have_click_dict.get("have_click_tractate", [])

        ###每次请求es去掉本卡片的ID
        if card_id:
            if card_type == CARD_TYPE.DIARY:
                have_click_diary.append(card_id)
            elif card_type == CARD_TYPE.ANSWER:
                have_click_question.append(card_id)
            elif card_type == CARD_TYPE.USERTOPIC:
                have_click_tractate.append(card_id)
            elif card_type == CARD_TYPE.ARTICLE:
                have_click_article.append(card_id)
        have_read_diary.extend(list(set(have_click_diary)))
        have_read_article.extend(list(set(have_click_article)))
        have_read_tractate.extend(list(set(have_click_tractate)))
        have_read_question.extend(list(set(have_click_question)))
        san_type_tags = []
        two_type_tags = []

        ###先获取当前点击的卡片的老标签和新标签
        for key, val in tag.items():
            if len(val) > 0:
                if key == "tags":
                    for item in val:
                        if "tag_type" in item.keys() and item.get("tag_type", None) == TAG_TYPE.BODY_PART_SUB_ITEM:
                            two_type_tags.append(item["id"])
                        if "type" in item.keys() and item.get("type", None) == TAG_TYPE.BODY_PART_SUB_ITEM:
                            two_type_tags.append(item["id"])
                        if "tag_type" in item.keys() and item.get("tag_type", None) == TAG_TYPE.ITEM_WIKI:
                            san_type_tags.append(item["id"])
                        if "type" in item.keys() and item.get("type", None) == TAG_TYPE.ITEM_WIKI:
                            san_type_tags.append(item["id"])
                        if "tag_type" in item.keys() and item.get("tag_type", None) != TAG_TYPE.CITY:
                            all_tags.append(item["id"])
                        if "type" in item.keys() and item.get("type", None) != TAG_TYPE.CITY:
                            all_tags.append(item["id"])

                if key == "new_tags":
                    new_all_tags = [item["id"] for item in val if len(item) > 0]
        ###diary
        if city_tag_id:
            sort_params["user_city_tag_id"] = city_tag_id
        elif city_id:
            try:
                x = City.objects.get(id=city_id)
                sort_params["user_city_tag_id"] = x.tag_id
            except City.DoesNotExist:
                pass

        diary_filters = {
            "is_sink": False,
            "has_before_cover": True,
            "has_after_cover": True,
            "content_level": [CONTENT_CLASS.EXCELLENT, CONTENT_CLASS.FINE, CONTENT_CLASS.GENERAL, 3.5]
        }
        ##article
        article_filters["content_level"] = [CONTENT_CLASS.EXCELLENT, CONTENT_CLASS.FINE, CONTENT_CLASS.GENERAL]
        ###answer
        question_filters['content_level'] = [CONTENT_CLASS.EXCELLENT, CONTENT_CLASS.FINE, CONTENT_CLASS.GENERAL]

        if len(all_tags) > 0:
            diary_filters["closure_tag_ids"] = all_tags
            article_filters["tag_ids"] = all_tags
            question_filters["tag_ids"] = all_tags
        if len(new_all_tags) > 0:
            tractate_filters["tag_ids"] = new_all_tags

        diary_query = recall_diary(None, offset=0, size=10, filters=diary_filters,
                                   sort_type=DIARY_ORDER_TYPE.RECOMMEND,
                                   sort_params=diary_sort_params,
                                   fields=["id", "user.id"], get_query=True, have_read_diary=list(have_read_diary),
                                   noarea_tags=noarea_tags, san_type_tags=san_type_tags, two_type_tags=two_type_tags,
                                   all_tags=all_tags)

        article_query = recall_articles(None, offset=0, size=10,
                                        filters=article_filters,
                                        sort_type=ARTICLE_SORT_TYPE.RECOMMEND, sort_params={},
                                        get_query=True, have_read_article=list(have_read_article),
                                        noarea_tags=noarea_tags, san_type_tags=san_type_tags,
                                        two_type_tags=two_type_tags, all_tags=all_tags,
                                        content_star_keyword=content_star_keyword)

        is_gray = recommed_service_category_device_id(device_id)

        if is_gray:
            question_query = recall_answers(None, offset=0, size=10, filters=question_filters,
                                            sort_type=ANSWER_SORT_TYPE.RECOMMEND,
                                            sort_params={},
                                            fields=["id", "user_id"], get_query=True,
                                            have_read_question=list(have_read_question),
                                            noarea_tags=noarea_tags, san_type_tags=san_type_tags,
                                            two_type_tags=two_type_tags, all_tags=all_tags,
                                            content_star_keyword=content_star_keyword,content_keyword=content_keyword)
        else:
            question_query = recall_answers(None, offset=0, size=10, filters=question_filters,
                                            sort_type=ANSWER_SORT_TYPE.RECOMMEND,
                                            sort_params={},
                                            fields=["id", "user_id"], get_query=True,
                                            have_read_question=list(have_read_question),
                                            noarea_tags=noarea_tags, san_type_tags=san_type_tags,
                                            two_type_tags=two_type_tags, all_tags=all_tags,
                                            content_star_keyword=content_star_keyword)

        tractate_query = tractate_sort(filters=tractate_filters, offset=0, size=10, query=None,
                                       use_fresh_tag=True,
                                       source_type=0,
                                       get_query=True, have_read_tractate=list(have_read_tractate),
                                       noarea_tags=noarea_tags, all_tags=new_all_tags,
                                       content_star_keyword=content_star_keyword)

        # 多索引排序
        question_index_name = es_index_adapt(index_prefix=settings.ES_INDEX_PREFIX, doc_type="answer", rw="read")
        tractate_index_name = es_index_adapt(index_prefix=settings.ES_INDEX_PREFIX, doc_type="tractate", rw="read")
        diary_index_name = es_index_adapt(index_prefix=settings.ES_INDEX_PREFIX, doc_type="diary", rw="read")
        article_index_name = es_index_adapt(index_prefix=settings.ES_INDEX_PREFIX, doc_type="article", rw="read")

        query_body = ""
        question_header_dict = {'index': question_index_name, 'type': "answer"}
        query_body += "{}\n{}\n".format(json.dumps(question_header_dict), json.dumps(question_query))

        tractate_header_dict = {'index': tractate_index_name, 'type': "tractate"}
        query_body += "{}\n{}\n".format(json.dumps(tractate_header_dict), json.dumps(tractate_query))

        diary_header_dict = {'index': diary_index_name, 'type': "diary"}
        query_body += "{}\n{}\n".format(json.dumps(diary_header_dict), json.dumps(diary_query))

        article_header_dict = {'index': article_index_name, 'type': "article"}
        query_body += "{}\n{}\n".format(json.dumps(article_header_dict), json.dumps(article_query))

        logging.info("[%s] get content_detail_tag  query_body diary_query :%s" % (device_id, diary_query))
        logging.info("[%s] get content_detail_tag  query_body article_query:%s" % (device_id, article_query))
        logging.info("[%s] get content_detail_tag  query_body question_query:%s" % (device_id, question_query))
        logging.info("[%s] get content_detail_tag  query_body tractate_query :%s" % (device_id, tractate_query))

        res = es_msearch(query_body)

        if len(res) > 0 and "responses" in res:
            for item in res["responses"]:
                if "hits" in item and "hits" in item["hits"] and len(item["hits"]["hits"]) > 0:
                    if item["hits"]["hits"][0]["_type"] == "answer":
                        question_results_list = item["hits"]["hits"]

                    elif item["hits"]["hits"][0]["_type"] == "tractate":
                        tractate_results_list = item["hits"]["hits"]

                    elif item["hits"]["hits"][0]["_type"] == "diary":
                        diary_results_list = item["hits"]["hits"]

                    elif item["hits"]["hits"][0]["_type"] == "article":
                        article_results_list = item["hits"]["hits"]

        ret_list = list()
        diary_index = 0
        answer_index = 0
        tractate_index = 0
        article_index = 0

        cur_get_num = 0
        while len(ret_list) < 10:

            cur_get_num += 1
            if card_type == CARD_TYPE.DIARY:
                diary_read_over, diary_index = _get_diary_ret_item(ret_list, diary_results_list, diary_index, 0,
                                                                   1, have_read_diary, 10)

                tractate_read_over, tractate_index = _get_tractate_ret_list(ret_list, tractate_results_list,
                                                                            tractate_index, 0, 1,
                                                                            have_read_tractate,
                                                                            10)
                answer_read_over, answer_index = _get_answer_ret_item(ret_list, question_results_list, answer_index, 0,
                                                                      1,
                                                                      have_read_question, 10)

                diary_read_over, diary_index = _get_diary_ret_item(ret_list, diary_results_list, diary_index, 0,
                                                                   1,
                                                                   have_read_diary, 10)
                tractate_read_over, tractate_index = _get_tractate_ret_list(ret_list, tractate_results_list,
                                                                            tractate_index, 0, 1,
                                                                            have_read_tractate,
                                                                            10)
                answer_read_over, answer_index = _get_answer_ret_item(ret_list, question_results_list, answer_index, 0,
                                                                      1,
                                                                      have_read_question, 10)

                article_read_over, article_index = _get_article_ret_item(ret_list, article_results_list, article_index,
                                                                         0,
                                                                         1, have_read_article, 10)

                diary_read_over, diary_index = _get_diary_ret_item(ret_list, diary_results_list, diary_index, 0,
                                                                   1,
                                                                   have_read_diary, 10)

                tractate_read_over, tractate_index = _get_tractate_ret_list(ret_list, tractate_results_list,
                                                                            tractate_index, 0, 1,
                                                                            have_read_tractate, 10)

                article_read_over, article_index = _get_article_ret_item(ret_list, article_results_list, article_index,
                                                                         0,
                                                                         1, have_read_article, 10)

                if diary_read_over and tractate_read_over and answer_read_over and article_read_over:
                    break

            if card_type == CARD_TYPE.USERTOPIC:
                tractate_read_over, tractate_index = _get_tractate_ret_list(ret_list, tractate_results_list,
                                                                            tractate_index, 0, 1,
                                                                            have_read_tractate,
                                                                            10)
                diary_read_over, diary_index = _get_diary_ret_item(ret_list, diary_results_list, diary_index, 0,
                                                                   1, have_read_diary, 10)
                answer_read_over, answer_index = _get_answer_ret_item(ret_list, question_results_list, answer_index, 0,
                                                                      1,
                                                                      have_read_question, 10)

                tractate_read_over, tractate_index = _get_tractate_ret_list(ret_list, tractate_results_list,
                                                                            tractate_index, 0, 1,
                                                                            have_read_tractate,
                                                                            10)
                diary_read_over, diary_index = _get_diary_ret_item(ret_list, diary_results_list, diary_index, 0,
                                                                   1,
                                                                   have_read_diary, 10)
                answer_read_over, answer_index = _get_answer_ret_item(ret_list, question_results_list, answer_index, 0,
                                                                      1,
                                                                      have_read_question, 10)

                article_read_over, article_index = _get_article_ret_item(ret_list, article_results_list, article_index,
                                                                         0,
                                                                         1, have_read_article, 10)
                tractate_read_over, tractate_index = _get_tractate_ret_list(ret_list, tractate_results_list,
                                                                            tractate_index, 0, 1,
                                                                            have_read_tractate,
                                                                            10)
                diary_read_over, diary_index = _get_diary_ret_item(ret_list, diary_results_list, diary_index, 0,
                                                                   1,
                                                                   have_read_diary, 10)

                article_read_over, article_index = _get_article_ret_item(ret_list, article_results_list, article_index,
                                                                         0,
                                                                         1, have_read_article, 10)

                if diary_read_over and tractate_read_over and answer_read_over and article_read_over:
                    break

            if (card_type == CARD_TYPE.ANSWER) or (card_type == CARD_TYPE.QUESTION):
                answer_read_over, answer_index = _get_answer_ret_item(ret_list, question_results_list, answer_index, 0,
                                                                      1,
                                                                      have_read_question, 10)
                tractate_read_over, tractate_index = _get_tractate_ret_list(ret_list, tractate_results_list,
                                                                            tractate_index, 0, 1,
                                                                            have_read_tractate,
                                                                            10)
                diary_read_over, diary_index = _get_diary_ret_item(ret_list, diary_results_list, diary_index, 0,
                                                                   1, have_read_diary, 10)

                answer_read_over, answer_index = _get_answer_ret_item(ret_list, question_results_list, answer_index, 0,
                                                                      1,
                                                                      have_read_question, 10)

                tractate_read_over, tractate_index = _get_tractate_ret_list(ret_list, tractate_results_list,
                                                                            tractate_index, 0, 1,
                                                                            have_read_tractate,
                                                                            10)

                diary_read_over, diary_index = _get_diary_ret_item(ret_list, diary_results_list, diary_index, 0,
                                                                   1,
                                                                   have_read_diary, 10)

                article_read_over, article_index = _get_article_ret_item(ret_list, article_results_list, article_index,
                                                                         0,
                                                                         1, have_read_article, 10)

                answer_read_over, answer_index = _get_answer_ret_item(ret_list, question_results_list, answer_index, 0,
                                                                      1,
                                                                      have_read_question, 10)
                tractate_read_over, tractate_index = _get_tractate_ret_list(ret_list, tractate_results_list,
                                                                            tractate_index, 0, 1,
                                                                            have_read_tractate,
                                                                            10)

                article_read_over, article_index = _get_article_ret_item(ret_list, article_results_list, article_index,
                                                                         0,
                                                                         1, have_read_article, 10)
                if diary_read_over and tractate_read_over and answer_read_over and article_read_over:
                    break

            if card_type == CARD_TYPE.ARTICLE:

                article_read_over, article_index = _get_article_ret_item(ret_list, article_results_list, article_index,
                                                                         0,
                                                                         1, have_read_article, 10)

                tractate_read_over, tractate_index = _get_tractate_ret_list(ret_list, tractate_results_list,
                                                                            tractate_index, 0, 1,
                                                                            have_read_tractate,
                                                                            10)

                diary_read_over, diary_index = _get_diary_ret_item(ret_list, diary_results_list, diary_index, 0,
                                                                   1, have_read_diary, 10)

                article_read_over, article_index = _get_article_ret_item(ret_list, article_results_list, article_index,
                                                                         0,
                                                                         1, have_read_article, 10)

                tractate_read_over, tractate_index = _get_tractate_ret_list(ret_list, tractate_results_list,
                                                                            tractate_index, 0, 1,
                                                                            have_read_tractate,
                                                                            10)
                diary_read_over, diary_index = _get_diary_ret_item(ret_list, diary_results_list, diary_index, 0,
                                                                   1, have_read_diary, 10)

                answer_read_over, answer_index = _get_answer_ret_item(ret_list, question_results_list, answer_index, 0,
                                                                      1,
                                                                      have_read_question, 10)

                article_read_over, article_index = _get_article_ret_item(ret_list, article_results_list, article_index,
                                                                         0,
                                                                         1, have_read_article, 10)

                tractate_read_over, tractate_index = _get_tractate_ret_list(ret_list, tractate_results_list,
                                                                            tractate_index, 0, 1,
                                                                            have_read_tractate,
                                                                            10)

                answer_read_over, answer_index = _get_answer_ret_item(ret_list, question_results_list, answer_index, 0,
                                                                      1,
                                                                      have_read_question, 10)

                if diary_read_over and tractate_read_over and answer_read_over and article_read_over:
                    break

        redis_have_read_dict = {
            "have_read_question": list(set(have_read_question)),
            "have_read_tractate": list(set(have_read_tractate)),
            "have_read_diary": list(set(have_read_diary)),
            "have_read_article": list(set(have_read_article))
        }
        redis_client.set(redis_key, json.dumps(redis_have_read_dict))
        redis_client.expire(redis_key, 60 * 10)
        redis_have_click_dict = {
            "have_click_question": list(set(have_click_question)),
            "have_click_tractate": list(set(have_click_tractate)),
            "have_click_diary": list(set(have_click_diary)),
            "have_click_article": list(set(have_click_article))
        }
        redis_client.set(have_click_data_key, json.dumps(redis_have_click_dict))
        redis_client.expire(have_click_data_key, 60 * 60 * 24)

        return ret_list

    except:
        logging_exception()
        logger.error("catch exception,err_msg:%s" % traceback.format_exc())
        return []


def _get_answer_ret_item(ret_list, answer_results_list, answer_index, score_base, get_num, answer_have_read_list, size):
    """
    获取问答数据
    :param ret_list:
    :param answer_results_list:
    :param answer_index:
    :return:
    """
    try:
        cur_index = 0
        have_read_over = False
        if len(answer_results_list) <= answer_index:
            return (True, answer_index)

        for answer_item in answer_results_list[answer_index:]:
            if cur_index < get_num and len(ret_list) < size:
                ret_answer_item = {
                    "id": int(answer_item["_id"]),
                    "type": CARD_TYPE.ANSWER
                }
                answer_have_read_list.append(answer_item["_id"])
                ret_list.append(ret_answer_item)
                answer_index += 1
                cur_index += 1
            else:
                break

        return (have_read_over, answer_index)
    except:
        logger.error("catch exception,err_msg:%s" % traceback.format_exc())
        return (True, answer_index)


def _get_diary_ret_item(ret_list, diary_results_list, diary_index, score_base, get_num, diary_have_read_list, size):
    """
    获取日记数据
    :param ret_list:
    :param diary_results_list:
    :param diary_index:
    :param score_base:
    :param get_num:
    :return:
    """

    try:
        cur_index = 0
        have_read_over = False
        if len(diary_results_list) <= diary_index:
            return (True, diary_index)

        for diary_item in diary_results_list[diary_index:]:

            if cur_index < get_num and len(ret_list) < size:
                ret_diary_item = {
                    "id": int(diary_item["_id"]),
                    "type": CARD_TYPE.DIARY
                }
                diary_have_read_list.append(diary_item["_id"])
                ret_list.append(ret_diary_item)
                diary_index += 1
                cur_index += 1
            else:
                break

        return (have_read_over, diary_index)
    except:
        logger.error("catch exception,err_msg:%s" % traceback.format_exc())
        return (True, diary_index)


def _get_tractate_ret_list(ret_list, tractate_results_list, tractate_index, score_base, get_num,
                           tractate_have_read_list, size):
    """
    获取帖子数据
    :param ret_list:
    :param tractate_results_list:
    :param tractate_index:
    :param score_base:
    :param get_num:
    :return:
    """
    try:
        cur_index = 0
        have_read_over = False
        if len(tractate_results_list) <= tractate_index:
            return (True, tractate_index)

        for tractate_item in tractate_results_list[tractate_index:]:
            if cur_index < get_num and len(ret_list) < size:
                ret_tractate_item = {
                    "id": int(tractate_item["_id"]),
                    "type": CARD_TYPE.USERTOPIC
                }
                tractate_have_read_list.append(tractate_item["_id"])
                ret_list.append(ret_tractate_item)
                tractate_index += 1
                cur_index += 1
            else:
                break

        return (have_read_over, tractate_index)
    except:
        logger.error("catch exception,err_msg:%s" % traceback.format_exc())
        return (True, tractate_index)


def _get_article_ret_item(ret_list, article_results_list, article_index, score_base, get_num,
                          article_have_read_list, size):
    """
    获取帖子数据
    :param ret_list:
    :param tractate_results_list:
    :param tractate_index:
    :param score_base:
    :param get_num:
    :return:
    """
    try:
        cur_index = 0
        have_read_over = False
        if len(article_results_list) <= article_index:
            return (True, article_index)

        for tractate_item in article_results_list[article_index:]:
            if cur_index < get_num and len(ret_list) < size:
                ret_tractate_item = {
                    "id": int(tractate_item["_id"]),
                    "type": CARD_TYPE.ARTICLE
                }
                article_have_read_list.append(tractate_item["_id"])
                ret_list.append(ret_tractate_item)
                article_index += 1
                cur_index += 1
            else:
                break

        return (have_read_over, article_index)
    except:
        logger.error("catch exception,err_msg:%s" % traceback.format_exc())
        return (True, article_index)
