#!/usr/bin/env python
# -*- coding: utf-8 -*-

# 问答卡片性能优化接口
from operator import itemgetter
from django.db.models import Q

from gm_rpcd.all import bind
from gm_types.error import ERROR
from gm_types.mimas import (
    MEDIA_IMAGE_URL_SOURCE,
    GRABBING_PLATFORM,
)

from qa.manager.qa_blend_manager import (
    qa_manager,
)
from qa.utils.decorator import listing
from qa.tasks import (
    add_answer_view,
)
from talos.services import UserConvertService
from utils.rpc import (
    gen,
    rpc_client,
    get_current_user,
    logging_exception,
)
from utils.group_routine import GroupRoutine


@bind('qa/question_answer/list_by_ids_v2')
@listing()
def get_qa_list_by_ids_v2(answer_ids, viewer_user_id=None):
    """
    通过回答id，获取卡片数据
    :param answer_ids:
    :param viewer_user_id:
    :return:
    """
    if not answer_ids:
        return []

    # 回答信息
    answer_ids = list(map(int, answer_ids))
    answer_objs = qa_manager.get_answer_objs(
        query=Q(pk__in=answer_ids, is_online=True, question__is_online=True),
        order_by=[]
    )
    answers_dic = qa_manager.get_answer_info_by_objs(
        answer_objs,
        viewer_user_id=viewer_user_id,
        need_social_info=True
    )  # sql查询

    # 问题信息
    question_ids = set(map(itemgetter("question_id"), answers_dic.values()))
    question_objs = qa_manager.get_question_objs(
        query=Q(pk__in=question_ids, is_online=True),
        order_by=[]
    )
    questions_dic = qa_manager.get_questions_info_by_objs(question_objs)  # sql查询

    answer_list = []
    valid_answer_ids = []

    for answer_id in answer_ids:
        _answer_data = answers_dic.get(answer_id, {})
        if _answer_data:
            _question_id = _answer_data.get("question_id", 0)
            _user_info = _answer_data.get("user_info", {})
            _answer_data.update({
                "question": questions_dic.get(_question_id, {}),
                "is_following": _user_info.get("is_following", False),
            })

            answer_list.append(_answer_data)
            valid_answer_ids.append(answer_id)

    add_answer_view.delay(answer_ids=valid_answer_ids)

    return answer_list


@bind("qa/question/new_answer_list/v2")
def get_new_answer_list_v2(answer_ids, viewer_user_id=None, return_sorted=False):
    """
    问题详情页回答列表，回答id来自策略推荐
    :param answer_ids:
    :param viewer_user_id: 当前浏览用户id
    :param return_sorted: 是否需要按照ids 排序
    :return:
    """
    result = {}
    if not answer_ids:
        return result

    answer_ids = qa_manager.filter_ids(answer_ids)
    answer_objs = qa_manager.get_answer_objs(
        query=Q(pk__in=answer_ids, is_online=True, question__is_online=True),
        order_by=[]
    )

    # header头图
    answer_header_images = qa_manager.answer_media.get_qa_header_images(qa_ids=answer_ids)
    # 其他信息
    user_ids = [answer.user_id for answer in answer_objs]
    pub_answer_nums_dic = qa_manager.get_user_publish_answer_nums(user_ids)
    vote_nums_dic = qa_manager.get_user_publish_answer_vote_nums(user_ids)

    # 回答信息
    answers_data = qa_manager.get_answer_info_by_objs(
        answer_objs,
        viewer_user_id=viewer_user_id,
        need_social_info=True,
        image_url_sources=[MEDIA_IMAGE_URL_SOURCE.CREATE]
    )

    for answer_id, answer_data in answers_data.items():
        _user_id = answer_data.get("user_id", 0)
        answer_data.update({
            "header_images": answer_header_images.get(answer_id, []),
            "answer_user_pub_nums": pub_answer_nums_dic.get(_user_id, 0),
            "answer_user_pub_favor_nums": vote_nums_dic.get(_user_id, 0),
        })
        result[str(answer_id)] = answer_data
    if return_sorted:
        result = sorted(result, key=lambda item: answer_ids.index(item.get('id')))

    return result


@bind("qa/answer_reply/include_sub_comments_for_answer_list")
def get_answer_reply_list_include_sub_comments(answer_ids, viewer_user_id=None, start_num=0, count=2):
    """
    获取问题详情页回答列表评论
    :param answer_ids:
    :param viewer_user_id:当前浏览用户id
    :param start_num:
    :param count:
    :return: {}
    """
    result = {}
    if not answer_ids:
        return result

    _reply_list, _map_dic = [], {}
    for answer_id in answer_ids:
        replies = list(qa_manager.get_objs_by_query_and_order(
            model=qa_manager.answer_replies.model,
            query=Q(answer_id=answer_id, is_online=True, first_reply__isnull=True),
            order_by=["id"]
        ).only("id", "user", "content", "create_time", "like_num")[start_num: start_num + count])
        _reply_list.extend(replies)
        _map_dic[answer_id] = [reply.id for reply in replies]

    replies_data = qa_manager.answer_replies.get_reply_data_by_replies_obj(
        replies=_reply_list,
        viewer_user_id=viewer_user_id,
        need_sub_comments=True
    )

    for answer_id, reply_ids in _map_dic.items():
        result[str(answer_id)] = [replies_data.get(reply_id, {}) for reply_id in reply_ids]

    return result


@bind("qa/question/get_question_rel_infos")
def get_question_rel_infos(question_id=None, answer_id=None):
    """
    获取问题关联的信息
    :param question_id: 问题id
    :return:
    """
    result = {}
    if not question_id and not answer_id:
        return result

    if answer_id:

        answer_obj = qa_manager.get_answer_objs(
            Q(pk=answer_id, is_online=True), None).only("question_id").first()
        if not answer_obj:
            return gen(ERROR.ANSWER_NOT_FOUND)

        question_id = answer_obj.question_id

    question_obj = qa_manager.get_question_objs(Q(pk=question_id), None).only("id", "user").first()
    if not question_obj:
        return gen(ERROR.QUESTION_NOT_FOUND)

    user = get_current_user()
    user_id = user and user.id
    if not question_obj.user_can_view(user_id):
        return gen(ERROR.QUESTION_NOT_FOUND)

    _question_id = question_obj.id
    v1_tags_info = qa_manager.question_manager.get_tags_info_by_question_ids([_question_id])
    v3_tags_info = qa_manager.question_manager.get_tags_v3_info_by_question_ids([_question_id])

    result.update({
        "v1_rel_tags_info": v1_tags_info.get(_question_id, []),
        "v3_rel_tags_info": v3_tags_info.get(_question_id, []),
        "rel_user_info": UserConvertService.get_user_info_by_user_id(question_obj.user_id)
    })

    return result


@bind("qa/answer/get_answer_rel_infos")
def get_answer_rel_infos(answer_id):
    """
    获取回答关联的信息
    :param answer_id:
    :return:
    """
    result = {}
    if not answer_id:
        return result

    answer_obj = qa_manager.get_answer_objs(
        Q(pk=answer_id, is_online=True), None).only("id", "user", "question_id").first()

    if not answer_obj:
        return gen(ERROR.ANSWER_NOT_FOUND)

    _rel_question_id = answer_obj.question_id
    routine = GroupRoutine()

    _map_list = [
        ("v1_rel_tags_info", qa_manager.question_manager.get_tags_info_by_question_ids, _rel_question_id, []),
        ("v3_rel_tags_info", qa_manager.answer_manager.get_tags_v3_info_by_answer_ids, answer_id, []),
        ("rel_user_info", UserConvertService.get_user_info_by_user_ids, answer_obj.user_id, {}),
    ]

    for key, func, param, _ in _map_list:
        routine.submit(key, func, [param])
    routine.go()

    for key, _, param, _default in _map_list:
        _data = routine.results.get(key, {})

        result.update({
            key: _data.get(param, _default)
        })

    return result


@bind('qa/answer/answer_bulk_offline_by_ids')
def answer_bulk_offline_by_ids(answer_ids, platform=None):
    """
    回答内容批量下线
    :param answer_ids:
    :param platform:
    :return:
    """
    if not answer_ids:
        return

    filter_query = Q(pk__in=list(map(int, answer_ids)))
    if platform and platform in GRABBING_PLATFORM:
        filter_query &= Q(platform=platform)

    nums = qa_manager.get_objs_by_query_and_order(
        model=qa_manager.answer_manager.model,
        query=filter_query
    ).update(is_online=False)

    return nums
