# coding=utf8

from __future__ import unicode_literals, absolute_import, print_function

import datetime
import json
from django.conf import settings
from django.db.models import Q, Count
from gm_rpcd.all import bind
from gm_types.error import ERROR as CODES
from gm_types.gaia import PROBLEM_FLAG_CHOICES, CONST_STRINGS
from gm_types.gaia import PROBLEM_ORDER_TYPE, FEED_ITEM_TYPE
from gm_types.gaia import TOPIC_ORDER_IN_DIARY, TOPIC_TYPE

from talos.decorators import cache_page, list_interface
from talos.libs.datetime_utils import get_timestamp_or_none
from talos.logger import info_logger
from talos.manager.topic import topic_list_manager
from talos.models.diary.diary import Diary
from talos.models.topic.topic import Problem
from talos.models.topic.topicvote import TopicVote
from talos.rpc import get_objects_from_queryset_and_pk_list, bind_context
from talos.services import UserService, UserConvertService
from talos.services import get_province_info_by_province_id
from talos.services import get_user_from_context
from talos.statistic import topic_view_increase_num
from talos.tools.reply_tool import get_topic_reply
from talos.models.topic.topicreply import TopicReply
from talos.libs.datetime_utils import get_timestamp_or_none
from utils.rpc import gen, assert_uint, rpc_client


@bind_context('topic/diary/topic_info')
def get_diary_topic_info(ctx, diary_id, start_num, count=10, topic_sort=TOPIC_ORDER_IN_DIARY.LATEST):
    """
    获取日记本下帖子详情接口, 只返回帖子相关信息, 请勿添加日记本信息
    """
    try:
        diary = Diary.objects.get(pk=diary_id)
    except Diary.DoesNotExist:
        return None
    user = get_user_from_context(ctx)
    topic_filter = Q(flag=PROBLEM_FLAG_CHOICES.NORMAL, is_online=True)
    topic_count = diary.topic_num

    end_num = start_num + count
    # v 7.6.25 排序规则更改 由之前按照 created_time 变更为 operation_date
    if topic_sort == TOPIC_ORDER_IN_DIARY.OLDEST:
        topics = diary.topics.filter(topic_filter).prefetch_related("images").order_by('operation_date', 'id')[start_num: end_num]
        topic_ids = list(topics.values_list('id', flat=True))
    else:
        topics = diary.topics.filter(topic_filter).prefetch_related("images").order_by('-operation_date', '-id')[start_num: end_num]
        topic_ids = list(topics.values_list('id', flat=True))
    #  v 7.6.45 增加判断点赞的状态
    voted_topic_ids = list(TopicVote.objects.filter(topic_id__in=topic_ids, user_id=user.id).values_list("topic_id", flat=True))

    # 获取每个日记帖前两个评论（根据时间倒序） 只有日记本的一级评论
    comment_topic = TopicReply.objects.filter(problem_id__in=topic_ids, replied_topic_id=None, is_online=True).\
        order_by('-reply_date').values('id', 'problem_id', 'user_id', 'content', 'reply_date')
    comments_count_info = TopicReply.objects.filter(problem_id__in=topic_ids).\
        values('problem_id').annotate(count=Count('id'))

    comment_dic, user_list, comment_count = {}, [], {}
    for comment_number in comments_count_info:
        _id = comment_number['problem_id']
        _count = comment_number['count']
        comment_count[_id] = _count

    limit_comment_number, comment_dic = 2, {}
    for comment in comment_topic:
        if len(comment_dic.get(comment['problem_id'], [])) >= limit_comment_number:
            continue
        user_list.append(comment.get('user_id'))
        comment_dic.setdefault(comment['problem_id'], []).append(comment)
    comment_user = UserConvertService.get_user_info_by_user_ids(user_list)

    topics_data = topic_list_manager.get_topic_list_data_for_diary_detail_page(topics)
    for topic in topics_data:
        topic['content'] = topic['content']
        topic_id = topic['id']
        if topic_sort == TOPIC_ORDER_IN_DIARY.OLDEST:
            topic['diary_num'] = start_num + topic_ids.index(topic_id) + 1
        else:
            topic['diary_num'] = topic_count - start_num - topic_ids.index(topic_id)
        #  当前用户点赞的状态
        if topic_id in voted_topic_ids:
            topic["is_liked"] = True
        else:
            topic["is_liked"] = False

        comments = comment_dic.get(topic_id, [])

        for comment in comments:
            user_comment = comment_user.get(comment['user_id'], {})
            comment.update({
                "nick_name": user_comment.get("user_name", ""),
                "reply_date": get_timestamp_or_none(comment.get('reply_date')),
                "comment_user_info": user_comment,  # 2019.08.16 外吐 user_info，用于信息整合
            })

        topic['comment_count'] = comment_count.get(topic_id, 0)
        topic['comments'] = comments
    return topics_data


@bind('topic/diary/topic_info_v2')
def get_diary_topic_info_v2(diary_id, start_num=0, count=10, topic_sort=TOPIC_ORDER_IN_DIARY.LATEST):
    """
    获取日记本下帖子详情接口, 只返回帖子相关信息, 请勿添加日记本信息，不处理用户相关的数据
    """
    topic_filter = Q(diary_id=diary_id, flag=PROBLEM_FLAG_CHOICES.NORMAL, is_online=True)
    query = Problem.objects.filter(topic_filter)
    # v 7.6.25 排序规则更改 由之前按照 created_time 变更为 operation_date
    if topic_sort == TOPIC_ORDER_IN_DIARY.OLDEST:
        query = query.order_by('operation_date', 'id')
    elif topic_sort == TOPIC_ORDER_IN_DIARY.LATEST:
        query = query.order_by('-operation_date', '-id')
    elif topic_sort == TOPIC_ORDER_IN_DIARY.MOST_COMMENT:
        query = query.order_by('-aggr__real_comment_num', 'id')
    topic_count = query.count()
    end_num = start_num + count
    topics = query[start_num: end_num]
    topic_ids = [t.id for t in topics]

    topics_data = topic_list_manager.get_topic_data_by_topics(topics)
    for topic in topics_data:
        topic_id = topic['id']
        if topic_sort == TOPIC_ORDER_IN_DIARY.OLDEST:
            topic['diary_num'] = start_num + topic_ids.index(topic_id) + 1
        else:
            topic['diary_num'] = topic_count - start_num - topic_ids.index(topic_id)
    return topics_data


@bind_context('topic/list_about_diary_for_ascle')
def get_diary_topic_info_for_ascle(ctx, diary_id, start_num, count=10):
    try:
        diary = Diary.objects.get(pk=diary_id)
    except Diary.DoesNotExist:
        return []

    user = get_user_from_context(ctx)
    topics = diary.topics.filter(flag=PROBLEM_FLAG_CHOICES.NORMAL, is_online=True).order_by('-created_time')[start_num: start_num + count]
    topics_data = topic_list_manager.get_list_data_by_topic_objs(topics, viewer_user_id=user.id)
    return topics_data


@bind('topic/diary_detail_for_pc')
def get_diary_topic_info_for_pc(diary_id, start_num=0, count=30, topic_sort=TOPIC_ORDER_IN_DIARY.LATEST):
    try:
        diary = Diary.objects.get(pk=diary_id)
    except Diary.DoesNotExist:
        return []

    topic_count = diary.topic_num
    if topic_sort == TOPIC_ORDER_IN_DIARY.LATEST:
        topics = diary.topics.filter(flag=PROBLEM_FLAG_CHOICES.NORMAL, is_online=True).order_by('-operation_date', '-id')[start_num: start_num + count]
    else:
        topics = diary.topics.filter(flag=PROBLEM_FLAG_CHOICES.NORMAL, is_online=True).order_by('operation_date', 'id')[start_num: start_num + count]

    topic_ids = list(topics.values_list('id', flat=True))
    return topic_list_manager.get_list_data_by_topic_objs_for_pc(topics, topic_sort, start_num, topic_count, topic_ids)


@bind_context('topic/filter')
@list_interface(offset_name='start_num', limit_name='count', element_model=Problem,
                element_func_list=[Problem.get_topic_info])
def topics_filter(ctx, start_num=0, count=10, filters={}, order_by=0):
    """get topics related to some `tag id` and other filters."""

    start_num = assert_uint(start_num, 0)
    count = assert_uint(count, 10)

    user = get_user_from_context(ctx)

    user_city_tag_id = None
    if order_by == PROBLEM_ORDER_TYPE.CITY:  # TODO cai 这段if逻辑应该进search模块
        if user:
            user_city_tag_id = user.city_tag_id

    result = rpc_client['api/topic/filter_topic'](
        offset=start_num,
        size=count,
        user_city_tag_id=user_city_tag_id,
        sort_type=order_by,
        filters=filters
    ).unwrap()
    topic_ids = result['topic_ids']

    return topic_list_manager.get_list_data_by_topic_ids(topic_ids, user.id)


@bind_context("topic/newest")
@list_interface(offset_name='start_num', limit_name="count", element_model=Problem)
def newest_diary_list(ctx, start_num=0, count=10):
    user = get_user_from_context(ctx)
    topic_ids = rpc_client['api/topic/filter_topic'](       # TODO CR 搜索
        offset=start_num,
        size=count,
        filters={
            'user_is_doctor': False,
        },
        sort_type=PROBLEM_ORDER_TYPE.LATEST_CREATED
    ).unwrap()['topic_ids']
    topic_view_increase_num(topic_ids)

    return {
        'topics': topic_list_manager.get_list_data_by_topic_ids(topic_ids, user.id)
    }


@bind_context('topic/community/hottest_topics')
@list_interface(offset_name='start_num', limit_name='count')
def get_community_hottest_topics(ctx, start_num=0, count=10):
    """
    NOTE:
            Desc: 获取社区首页的最热信息
            :param ctx:
            :param start_num:
            :param count:
            :return:
            version: v5.6
    """
    user = get_user_from_context(ctx)
    query = {'topic_vote_count_gte': settings.HOT_TOPIC_VOTE_THRESHOLD}

    if user:
        user_followed_tags = UserService.user_followed_tags_obj(user.id)
        if user_followed_tags:
            query['raw_tag_ids'] = [tag.id for tag in user_followed_tags]

    es_res = rpc_client['api/topic/filter_topic'](offset=start_num, size=count, filters=query).unwrap()     # TODO CR 搜索

    """ 如果用户登录，但是关注的圈子中没有多于40的，则显示全部 """
    if 'topic_ids' in es_res and not es_res['topic_ids'] and 'raw_tag_ids' in query:
        # fixbug res_res['topic_ids'] can be []
        del query['raw_tag_ids']
        es_res = rpc_client['api/topic/filter_topic'](offset=start_num, size=count, filters=query).unwrap()  # TODO CR 搜索

    topic_ids = es_res['topic_ids']

    topic_view_increase_num(topic_ids)

    return topic_list_manager.get_list_data_by_topic_ids(topic_ids, user.id)


@bind_context('topic/hot_in_24hrs')
@list_interface(limit_name='count', element_model=Problem)
def hot_in_24hrs(ctx, count=20):
    # 接口已无访问
    # user = get_user_from_context(ctx)
    # topic_ids = hot_in_24hrs_cache.get('topics') or '[]'
    # topic_ids = json.loads(topic_ids)
    # return topic_list_manager.get_list_data_by_topic_ids(topic_ids, user.id)
    # v 7.6.65 更改 该功能不再使用！
    return []


@bind_context('topic/take_sofa/get', login_required=True)
@list_interface(offset_name='start_num', limit_name='count')
def api_diary_take_sofa_get(ctx, count=10, start_num=0):
    user = get_user_from_context(ctx)
    topics = Problem.objects.filter(
        is_online=True, reply_num=0
    ).order_by('-id')[start_num:start_num + count]
    return topic_list_manager.get_list_data_by_topic_objs(topics, user.id)


@bind_context("topic/user_topics")
@list_interface(
    offset_name='start_num',
    limit_name='count',
    element_model=Problem
)
def api_topic_topics(ctx, user_id, count=10, start_num=0, without_activity_topics=False):
    """get user topics infomation.

    .. changelog. add param without_activity_topics at 5.5

    TODO: delete without_activity_topics when mweb support activities
    """
    # user who is viewing pages
    user = get_user_from_context(ctx)

    t_user = UserService.get_user_by_user_id(user_id)
    # user is viewing user_t's personal page
    if t_user is None:
        return gen(CODES.USER_NOT_FOUND)

    topic_filter = Q(is_online=True, user_id=t_user.id)
    diary_q = Q(diary__isnull=True) | (
        Q(diary__isnull=False) & Q(diary__is_online=True))
    topic_filter = topic_filter & diary_q

    if without_activity_topics:
        topic_filter &= Q(activity__isnull=True)

    problems = Problem.objects.filter(topic_filter).order_by('-created_time')
    problems = problems[start_num:start_num + count]

    topic_ids = [p.id for p in problems]
    topic_view_increase_num(topic_ids)

    return topic_list_manager.get_list_data_by_topic_objs(problems, user.id)


# @bind_context("talos/topics_my", login_required=True)
# @bind_context("talos/topic/my_list", login_required=True)
# @list_interface(offset_name='start_num', limit_name='count', element_model=Problem)
# def get_topics_my(ctx, count=10, start_num=0):
#     """我发布的话题列表
#        count: 每次请求记录条数, 默认为10
#        start_num: 起始条数, 默认为0
#     """
#     user = get_user_from_context(ctx)
#
#     topic_filter = Q(
#         flag=PROBLEM_FLAG_CHOICES.NORMAL,
#         is_online=True,
#         user_id=user.id
#     )
#     problems = Problem.objects.filter(
#         topic_filter
#     ).order_by('-last_modified', "-id")[start_num: start_num + count]
#
#     return topic_list_manager.get_list_data_by_topic_objs(problems)

def _topics_doctor_common_func(doctor_id, user, count, start_num):
    """
        医生帖子公共接口
    :param doctor_id: 医生id
    :param user: 通过上下文获取的用户对象
    :param count:  展示的个数
    :param start_num:  起始位置
    :return: () tuple (counts, topics)
    """

    user_id = UserService.get_user_id_by_doctor_id(doctor_id)
    if not user_id:
        return

    topic_filter = Q(
        flag=PROBLEM_FLAG_CHOICES.NORMAL,
        is_online=True,
        user_id=user_id
    )
    problems = Problem.objects.filter(topic_filter).exclude(
        topic_type=TOPIC_TYPE.COLUMN_ARTICLE
    ).order_by('-created_time')
    topics_count = problems.count()

    problems = problems[start_num:start_num + count]

    topic_ids = [p.id for p in problems]
    topic_view_increase_num(topic_ids)
    topics = topic_list_manager.get_list_data_by_topic_objs(problems, user.id)

    return topics_count, topics


@bind_context("topic/topics/doctor")
@list_interface(offset_name='start_num', limit_name='count', element_model=Problem,
                element_func_list=[Problem.get_topic_info])
def api_topic_topics_doctor(ctx, doctor_id, count=10, start_num=0):
    result = []

    user = get_user_from_context(ctx)
    res = _topics_doctor_common_func(doctor_id, user, count, start_num)
    if not res:
        return result

    return res[1]


@bind_context("topic/topics/doctor/v1")
@list_interface(offset_name='start_num', limit_name='count', element_model=Problem,
                element_func_list=[Problem.get_topic_info])
def api_topic_topics_doctor_v1(ctx, doctor_id, count=10, start_num=0):
    result = {
        "total_count": 0,
        "topics": [],
    }

    user = get_user_from_context(ctx)
    res = _topics_doctor_common_func(doctor_id, user, count, start_num)
    if not res:
        return result

    result["total_count"] = res[0]
    result["topics"] = res[1]

    return result


@bind_context("topic/doctor_topics/v2")
@list_interface(limit_name='count')
def api_topic_topics_doctor_v2(ctx, doctor_id, count=10, start_num=0, is_hospital=False):
    """
    v 7.6.25 改版  获取医生发布的 直播,专栏  count 代表获取每种类型的个数
    :param ctx:
    :param doctor_id: # 医生id
    :param count:  获取个数
    :param start_num: 起始位置
    :return: result 字典
    """
    result = {
        'total_count': 0,
        'topics': [],
        'zhibo': [],  # 直播, call live service to get this data
        'article': [],  # 专栏
    }
    user_id = UserService.get_user_id_by_doctor_id(doctor_id)
    if user_id is None:
        return result

    topic_filter = Q(
        flag=PROBLEM_FLAG_CHOICES.NORMAL,
        is_online=True,
        user_id=user_id
    )
    problems = Problem.objects.filter(topic_filter).order_by('-created_time')
    result['total_count'] = problems.count()

    user = get_user_from_context(ctx)

    # 专栏 + 优质用户文章
    articles = problems.filter(
        topic_type__in=(TOPIC_TYPE.COLUMN_ARTICLE, TOPIC_TYPE.USER_ARTICLE)
    )[start_num:start_num + count]
    result["article"] = topic_list_manager.get_list_data_by_topic_objs(articles, user.id, need_service_or_live_reply=not is_hospital)

    problems = problems[start_num:start_num + count]
    result['topics'] = topic_list_manager.get_list_data_by_topic_objs(problems, user.id, need_service_or_live_reply=not is_hospital)

    topic_ids = [p.id for p in list(articles) + list(problems)]
    topic_view_increase_num(list(set(topic_ids)))

    return result


@bind_context("topic/list_for_doctor")
@list_interface(
    offset_name='start_num', limit_name='count', element_model=Problem, element_func_list=[Problem.get_topic_info])
def get_topics(
        ctx, count=10, start_num=0, bodypart_tag_id=None, topic_type_id=u'', topic_types=[],
        province_id=CONST_STRINGS.NATIONWIDE, order_by=PROBLEM_ORDER_TYPE.TO_BE_ANSWERED):
    """话题列表
       count: 每次请求记录条数, 默认为10
       start_num: 起始条数, 默认为0
       bodypart_tag_id: 一级分类筛选
       topic_type_id: 话题类型筛选(咨询帖、其他帖)
       province_id: 省份筛选, 默认为全国
    """
    result = []
    user = get_user_from_context(ctx)

    filters = {
        'is_topic': True,
        'is_public': True,
    }

    if bodypart_tag_id:
        filters['tag_ids'] = [bodypart_tag_id, ]

    if topic_type_id:
        # TODO Deprecated 咨询帖和讨论帖合并, 医生版需要展示这两种帖子
        filters['topic_type'] = topic_type_id

    elif topic_types:
        filters['topic_types'] = topic_types

    if province_id and province_id != CONST_STRINGS.NATIONWIDE:
        province = get_province_info_by_province_id(province_id)
        if province is not None:
            filters['province_tag_id'] = province.tag_id

    data = rpc_client['api/topic/filter_topic'](offset=start_num, size=count, filters=filters, sort_type=order_by).unwrap()
    ids = data['topic_ids']
    result = topic_list_manager.get_list_data_by_topic_ids(ids, user.id)
    return result


@bind_context('topic/list_data_get_by_ids')
def talos_topic_list_data_get_by_ids(ctx, ids):
    assert len(ids) < 100, 'too many topic_ids'
    user = get_user_from_context(ctx)

    topics = get_objects_from_queryset_and_pk_list(
        Problem.objects.all(), ids
    )
    result = {
        'topics': topic_list_manager.get_list_data_by_topic_objs(topics, user.id)
    }

    topic_view_increase_num(ids)
    return result


@bind('topic/sitemap')
@cache_page(2 * 60)
def get_topiclist_sitemap():
    topic_info = []
    topic_filter = Q(flag=PROBLEM_FLAG_CHOICES.NORMAL,
                     is_online=True,
                     is_public=True,
                     is_topic=True,
                     created_time__gt=datetime.datetime(2013, 9, 1))
    problems = Problem.objects.filter(topic_filter)
    problems = problems.order_by('-id')[0:settings.BUILD_SITEMAP_COUNT]
    for problem in problems:
        topic_info.append({
            'id': problem.id,
            'last_modified': get_timestamp_or_none(problem.last_modified),
        })
    return topic_info


@bind_context("topic/user_topics_v2")
@list_interface(
    offset_name='start_num',
    limit_name='count',
    element_model=Problem
)
def api_topic_topics_v2(ctx, user_id, count=10, start_num=0):
    """get user topics infomation.
    added 7.1.5
    筛选帖子类型：咨询，讨论，免费活动
    """
    # user who is viewing pages
    user = get_user_from_context(ctx)

    t_user = UserService.get_user_by_user_id(user_id)
    # user is viewing user_t's personal page
    if t_user is None:
        return gen(CODES.USER_NOT_FOUND)

    topic_filter = Q(is_online=True, user_id=t_user.id) & (Q(topic_type=TOPIC_TYPE.ACTIVITY))

    problems = Problem.objects.filter(topic_filter).order_by('-created_time')
    problems = problems[start_num:start_num + count]

    topic_ids = [p.id for p in problems]
    topic_view_increase_num(topic_ids)

    return topic_list_manager.get_list_data_by_topic_objs(problems, user.id)


@bind_context('topic/feed/video_feed')
def get_video_feed(ctx, start_num=0, count=10):
    user = get_user_from_context(ctx)

    topic_ids = rpc_client['api/topic/filter_topic'](
        offset=start_num, size=count,
        sort_type=PROBLEM_ORDER_TYPE.DEFAULT, filters={'has_video': True}
    ).unwrap()

    topic_view_increase_num(topic_ids['topic_ids'])

    feed_infos = []
    topic_infos = topic_list_manager.get_list_data_by_topic_ids(topic_ids['topic_ids'], user.id)
    topic_dict = {str(topic['problem']['topic_id']): topic for topic in topic_infos}
    for topic_id in topic_ids['topic_ids']:
        if str(topic_id) not in topic_dict:
            continue

        feed_info = topic_dict[str(topic_id)]
        feed_info['id'] = topic_id
        feed_info['item_type'] = FEED_ITEM_TYPE.TOPIC
        feed_info['comments'] = []
        feed_infos.append(feed_info)

    return feed_infos


@bind("topic/list_for_mip")
@cache_page(2 * 60 * 60)
def get_diary_topic_list_for_mip(diary_id):
    """
    mip百度合作，日记本详情页帖子列表
    :param diary_id:
    :return:
    """
    try:
        diary = Diary.objects.get(pk=diary_id, is_online=True)
    except Diary.DoesNotExist:
        return gen(CODES.DIARY_NOT_FOUND)

    topics = Problem.objects.filter(diary=diary, flag=PROBLEM_FLAG_CHOICES.NORMAL, is_online=True).order_by(
        "-operation_date", "-id")

    return topic_list_manager.get_topic_list_data_for_diary_detail_page(topics)