# coding=utf-8
from django.conf import settings
from django.contrib.auth.models import User
from django.db.models import Max

from gm_types.gaia import TAG_TYPE

from api import Service
from api.models.area import City
from api.models.tickets import Punishment

from hippo.models import Doctor
from hippo.models import Hospital
from talos.models.diary.diary import Problems
from talos.models.diary import DiaryCheck, RelatedRecommendScore
from api.models import FeedOperateV2
from talos.models.topic import TopicReply, TopicVote
from talos.models.diary.diaryfeed import TIDiaryScore
# from hippo.models import ClassifyUser
from statistic.models import ClassifyUser

from .es import tzlc
from .transfer import get_area_tag_info, MIN_TIME
from search.utils.area import get_nearby_province_tag
from rpc.context import get_gaia_local_invoker
from .lambdamart_online_model import evalOneContent, getRedisCli, getGlobalMaxNum
from api.tool.log_tool import logging_exception
import math
import datetime
from gm_types.gaia import USER_CLASSIFY, HOSPITAL_TYPE
from talos.models.topic.topicreply import TopicReply
import logging
import time
from agile.services import (
    AgileTagService,
    AgileTagTypeService,
    AgileTagMappingTagService,
    AgileTagRecommendTypeService,
    AgileTagRelationPolymerService,
)


def get_diary(instance):
    d = instance
    from talos.models.diary import Diary
    assert isinstance(d, Diary)

    diary_cover = d.cover
    res = {
        'id': d.id,
        'is_sink': d.is_sink,
        'is_online': d.is_online,
        'is_headline': d.is_headline,
        'is_identification': d.is_identification,
        'is_elite': d.is_essence,
        'has_video_cover': d.has_video_cover,
        'has_cover': True if diary_cover else False,
        'has_before_cover': True if diary_cover and 'Before' in [c['desc'] for c in diary_cover] else False,
        'has_after_cover': True if diary_cover and 'After' in [c['desc'] for c in diary_cover] else False,
        'created_time': tzlc(d.created_time),
        'is_rating_5': int(d.rating) == 5,
        'vote_num': d.vote_num,
        'last_topic_add_time': tzlc(d.last_topic_add_time),
        'sticky_post': d.sticky_post,
        # 医生医院自定义排序默认值
        'doctor_customize_sort': 9223372036854775807,  # 2**63-1
        'hospital_customize_sort': 9223372036854775807,  # 2**63-1
        'stick_priority': d.stick_priority,
        "title": d.title,
        "answer": d.get_diary_answer(),
        "good_click":d.get_good_click,
        "is_promote":d.get_cpc,
        "is_low_quality":d.get_low_quality
    }
    res["before_cover_url"] = ""
    res["after_cover_url"] = ""
    if diary_cover:
        for c in diary_cover:
            if "Before" == c["desc"]:
                res["has_before_cover"] = True
                res["before_cover_url"] = c["image"]
            elif "After" == c["desc"]:
                res["has_after_cover"] = True
                res["after_cover_url"] = c["image"]

    # 三种分数
    res['heat_score'], res['audit_score'], res['choucheng_score'] = d.get_index_rank()
    # 额外的分数
    try:
        res['additional_score'] = d.diary_rank.additional_score
    except Exception:
        res['additional_score'] = 0

    res['normal_topic_count'] = d.topics.filter(is_online=True, flag__exact='n').count()

    user_classify_val = -1
    user_classify_object = ClassifyUser.objects.filter(user_id=d.user_id).first()
    if user_classify_object and hasattr(user_classify_object, "classify"):
        user_classify_val = int(user_classify_object.classify)

    res["user_classify"] = user_classify_val

    user = User.objects.get(id=d.user_id)
    v_user = {
        'id': d.user_id,
        'last_name': user.last_name,
    }
    if hasattr(user, 'userextra'):
        v_user.update(get_area_tag_info(user.userextra.city))
    res['user'] = v_user

    doctor_tag_id = -1
    if d.doctor_id:
        doctor = Doctor.objects.get(id=d.doctor_id)
        v_doctor = {
            'id': doctor.id,
            'name': doctor.name,
            'is_authenticated': True if (doctor.phone and doctor.is_online) else False
        }
        if doctor.hospital:
            v_doctor['hospital'] = get_area_tag_info(doctor.hospital.city)
            v_doctor['hospital']['name'] = doctor.hospital.name
            v_doctor['hospital']['id'] = doctor.hospital.id
            if doctor.hospital.officer:
                v_doctor['hospital']['officer_name'] = doctor.hospital.officer.name
            # 添加公立／私立TAG
            try:
                doctor_tag_id = settings.PUBLIC_TAG_ID if doctor.hospital.hospital_type == HOSPITAL_TYPE.PUBLIC else settings.PRIVATE_TAG_ID
            except AttributeError:
                # 医生未关联Hospital
                pass

        # 罚单及日记本首页限流
        punishment = Punishment.get_punishment_by_doctor_id(doctor.id).get('diary', None)
        if punishment and punishment.get('type', None) in ['limit', ]:
            res['merchant_sink_start_time'] = tzlc(punishment['start_time'])
            res['merchant_sink_end_time'] = tzlc(punishment['end_time'])
        elif punishment and punishment.get('type', None) == 'weight':
            # start,end,weight,type
            res['index_limit_start_time'] = tzlc(punishment['start_time'])
            res['index_limit_end_time'] = tzlc(punishment['end_time'])
            res['index_limit_weight2'] = punishment['factor']
        else:
            # something wrong with punishment data
            pass

        res['doctor'] = v_doctor

        if not doctor.is_online:
            res['is_sink'] = True

        # 医生自定义的排序
        doc_custom_sort = doctor.diary_ranks.filter(diary_id=d.id)
        if doc_custom_sort:
            res['doctor_customize_sort'] = doc_custom_sort[0].rank

    else:
        res['doctor'] = {
            'is_authenticated': False
        }

    res["diary_city"] = -1

    try:
        if "hospital" in res["doctor"] and "city_tag_id" in res["doctor"]["hospital"] and res["doctor"]["hospital"][
            "city_tag_id"] > 0:
            res["diary_city"] = res["doctor"]["hospital"]["city_tag_id"]
        elif "hospital" in res and "city_tag_id" in res["hospital"]:
            res["diary_city"] = res["hospital"]["city_tag_id"]
        elif "city_tag_id" in res["user"] and res["user"]["city_tag_id"] > 0:
            res["diary_city"] = res["user"]["city_tag_id"]
    except:
        pass

    # 是否运营位
    cur_time = str(datetime.datetime.now())
    results = FeedOperateV2.objects.filter(start_time__lte=cur_time,
                                           end_time__gte=cur_time, is_online=True, card_type=0,
                                           card_id=res["id"])

    if results:
        res["is_operate"] = True
    else:
        res["is_operate"] = False

    if d.service_id:
        service = Service.objects.get(id=d.service_id)
        res['service'] = {
            'id': str(service.id),
            'name': service.name,
            'rating': service.rating,
            'short_description': service.short_description,
        }
        # 计算关联美购评分评级
        if service.rating >= 5:
            res['service_rating_level_double'] = settings.DIARY_SERVICE_RATING_LEVEL['GTE_5']
        elif service.rating >= 4.8:
            res['service_rating_level_double'] = settings.DIARY_SERVICE_RATING_LEVEL['GTE_4_8']
        elif service.rating >= 4.5:
            res['service_rating_level_double'] = settings.DIARY_SERVICE_RATING_LEVEL['GTE_4_5']
        elif service.rating >= 4:
            res['service_rating_level_double'] = settings.DIARY_SERVICE_RATING_LEVEL['GTE_4']
        else:
            res['service_rating_level_double'] = settings.DIARY_SERVICE_RATING_LEVEL['LT_4']
        res['has_service'] = True
        if service.doctor:
            res['service']['doctor_id'] = service.doctor_id
        if not service.is_online:
            res['is_sink'] = True
        special_maps = service.get_can_sell_item_ids_and_current_special_id()
        special_ids = special_maps.values()
        res['service']['special_ids'] = special_ids

    else:
        res['has_service'] = False
        res['service_rating_level_double'] = settings.DIARY_SERVICE_RATING_LEVEL['LT_4']

    if d.hospital_id:
        hospital = Hospital.objects.get(id=d.hospital_id)
        v_hospital = {
            'id': hospital.id,
            'name': hospital.name,
        }
        v_hospital.update(get_area_tag_info(hospital.city))
        res['hospital'] = v_hospital

        # 医院自定义的排序
        hos_doc = hospital.doctor_hospital.first()
        officer = None
        if hos_doc:
            officer = hos_doc.get_officer()
        if officer:
            hos_custom_sort = officer.diary_ranks.filter(diary_id=d.id)
            if hos_custom_sort:
                res['hospital_customize_sort'] = hos_custom_sort[0].rank
        # 添加公立／私立TAG
        try:
            doctor_tag_id = settings.PUBLIC_TAG_ID if hospital.hospital_type == HOSPITAL_TYPE.PUBLIC else settings.PRIVATE_TAG_ID
        except AttributeError:
            # 医生未关联Hospital
            pass

    # 3级tag?
    tags = d.tags
    res['tags'] = [t.name for t in tags]
    # tag闭包
    closure_tags = get_gaia_local_invoker()['api/tag/closure_tags'](
        tag_ids=[tag.id for tag in tags],
        is_online_only=True)
    res['closure_tag_ids'] = [t['id'] for t in closure_tags.unwrap()]
    if doctor_tag_id != -1:
        res['closure_tag_ids'].append(doctor_tag_id)

    # 新标签
    ori_tag_id_list = [tag.id for tag in tags]
    fresh_tag_info_list = list(AgileTagMappingTagService.get_mapping_tags_tuple_by_old_tag_ids(ori_tag_id_list))
    fresh_tag_id_list = list()
    fresh_tag_name_list = list()
    for id, name in fresh_tag_info_list:
        fresh_tag_id_list.append(id)
        fresh_tag_name_list.append(name)
    res["fresh_tags"] = fresh_tag_name_list
    res["fresh_closure_tag_ids"] = fresh_tag_id_list

    res['popularity'] = d.reply_num
    res['popularity'] += TopicVote.objects.filter(topic__is_online=True, topic__diary=d).count()

    res['last_update_time'] = d.last_modified
    problem_update = d.topics.aggregate(Max('last_modified'))
    if problem_update['last_modified__max']:
        res['last_update_time'] = max(res['last_update_time'], problem_update['last_modified__max'])
    res['last_update_time'] = tzlc(res['last_update_time'])

    # WARNING:
    # This code *MUST* be synchronized with 'diary' in trans2es.type_info
    # REGION BEGIN
    k1, k2 = 'annotate__topicreply__reply_date__max', 'annotate__topics__topicreply__reply_date__max'
    if hasattr(d, k1) and hasattr(d, k2):
        v1 = getattr(d, k1)
        v2 = getattr(d, k2)
    else:
        v1 = TopicReply.objects.filter(diary_id=d.id).aggregate(Max('reply_date'))['reply_date__max']
        v2 = TopicReply.objects.filter(problem__diary_id=d.id).aggregate(Max('reply_date'))['reply_date__max']

    if not v1:
        last_any_reply_time = v2
    elif not v2:
        last_any_reply_time = v1
    else:
        last_any_reply_time = max(v1, v2)
    # REGION END

    last_any_reply_time = tzlc(last_any_reply_time) or MIN_TIME
    res['last_any_reply_time'] = last_any_reply_time

    res['author_last_update_time'] = d.created_time
    author_last_update_time = TopicReply.objects.filter(problem__diary=d, user_id=d.user_id).aggregate(
        Max('reply_date'))
    if author_last_update_time['reply_date__max']:
        res['author_last_update_time'] = max(res['author_last_update_time'], author_last_update_time['reply_date__max'])
    res['author_last_update_time'] = tzlc(res['author_last_update_time'])

    # content level
    try:
        audit = d.diary_check.order_by('-id').first()
        if audit is None:
            res['content_level'] = None
        else:
            res['content_level'] = audit.content_level
    except DiaryCheck.DoesNotExist:
        res['content_level'] = None

    res['content_level_is_good'] = False
    try:
        content_level_is_good = int(d.content_level) >= 4
        res['content_level_is_good'] = content_level_is_good
    except (ValueError, TypeError):
        pass

    # try:
    #     redis_cli = getRedisCli()
    #     (diaryMaxDiaryTotalClickNum, diaryQueryMaxScore, diaryMaxPopularity, diaryMaxVoteNum) = getGlobalMaxNum()
    #
    #     itemContentLeverisGoodWeight = 0
    #     if res["content_level_is_good"]:
    #         itemContentLeverisGoodWeight = 0.01
    #
    #     itemPopularityWeight = (float(res['popularity']) / diaryMaxPopularity) * 3.0
    #     itemHasServiceWeight = 0
    #     if res['has_service']:
    #         itemHasServiceWeight = 0.1
    #
    #     itemVoteNumWeight = (float(res["vote_num"]) / diaryMaxVoteNum) * 3.0
    #
    #     itemClickNumWeight = 0
    #     redis_click_num = redis_cli.hget("search_ltr:diary_have_been_clicked", res["id"])
    #     if redis_click_num and int(redis_click_num) > 0:
    #         itemClickNumWeight = (float(redis_click_num) / diaryMaxDiaryTotalClickNum) * 10.0 + 3.0
    #
    #     content_data = "1" + " qid:1" + " 1:" + str(itemContentLeverisGoodWeight) + " 2:" + str(
    #         itemPopularityWeight) + " 3:" + str(itemHasServiceWeight) + " 4:" + str(itemVoteNumWeight) + " 5:" + str(
    #         itemClickNumWeight)
    #     (query_document_id, ltr_score) = evalOneContent(content_data)
    #     res["ltr_score"] = ltr_score
    # except:
    #     res["ltr_score"] = 1.0
    #     logging_exception()

    # order info
    if d.order_id:
        res['has_order'] = True
    else:
        res['has_order'] = False

    res["offline_score"] = 0
    if res["is_headline"]:
        res["offline_score"] += 50
    if res["is_identification"]:
        res["offline_score"] += 40
    if res["has_order"]:
        res["offline_score"] += 30
    if res["has_service"]:
        res["offline_score"] += 20
    if res["is_elite"]:
        res["offline_score"] += 10
    if res["popularity"] > 0:
        res["offline_score"] += math.log(res["popularity"])
    if res["user_classify"] > 0 and res["user_classify"] != USER_CLASSIFY.MODEL:
        res["offline_score"] += 60

    try:
        if int(d.content_level) == 5:
            res["offline_score"] += 400
        elif int(d.content_level) == 4:
            res["offline_score"] += 300
        elif float(d.content_level) == 3.5:
            res["offline_score"] += 250

        # 单图降权
        if not res["has_before_cover"] or not res["has_after_cover"]:
            res["offline_score"] -= 400

        cur_time = int(time.time())
        if "merchant_sink_start_time" in res and "merchant_sink_end_time" in res:
            sink_start = int(time.mktime(res["merchant_sink_start_time"].timetuple()))
            sink_end = int(time.mktime(res["merchant_sink_end_time"].timetuple()))

            if sink_start <= cur_time and cur_time < sink_end:
                res["offline_score"] -= 10000
    except (ValueError, TypeError):
        pass

    res['offline_score_v1'] = d.get_new_diary_score()

    # http://wiki.wanmeizhensuo.com/pages/viewpage.action?pageId=5475683
    # add related recommend data
    try:
        rs = RelatedRecommendScore.objects.get(diary_id=d.id)
        r_score = rs.score
    except RelatedRecommendScore.DoesNotExist:
        r_score = 0
    res['recommend_score'] = r_score

    # add nearby city tags
    res['nearby_city_tags_v1'] = []
    city_tag = filter(lambda x: x.tag_type == TAG_TYPE.CITY, d.tags)
    if city_tag:
        cs = City.objects.filter(tag_id=city_tag[0].id)
        if cs:
            cts = get_nearby_province_tag(cs[0].id)
            res['nearby_city_tags_v1'] = cts
    try:
        # score = TIDiaryScore.objects.get(diary_id=d.id)
        res['feed_score'] = 1
    except TIDiaryScore.DoesNotExist:
        pass

    # 获取热度分
    # 获得该日记本下的日记帖
    now = datetime.datetime.now()
    three_day = datetime.datetime.now() - datetime.timedelta(days=60)
    yesterday_begin_time = "%s-%s-%s 00:00:00" % (three_day.year, three_day.month, three_day.day)
    data = Problems.objects.filter(user_id=d.user_id, topic_type__in=["0", "1", "2"],
                                   diary_id=d.id, is_online=True).values_list("id", flat=True)

    logging.info("get data:%s" % data)
    reply_num = TopicReply.objects.filter(problem_id__in=data, reply_date__gte=yesterday_begin_time,
                                          reply_date__lte=now,
                                          is_online=True).count()
    logging.info("get reply_num:%s" % reply_num)
    res["hot_score"] = d.get_hot_score(reply_num)

    return res
