# coding=utf-8
import math

from django.conf import settings
from django.utils import timezone
from gm_types.gaia import TAG_TYPE, ADVER_MANAGEMENT_POSITION_TYPE, DOCTOR_TYPE, HOSPITAL_TYPE

from answer.models import Answer
from api.business.tag import TagControl
from api.models import AdvertiseManagement, ServiceTag, Tag, Doctor
from api.models.message import Message
from api.models.tickets import Punishment

from statistic.models import DoctorRankFactor
from hippo.models import MerchantRelevance
from talos.models.diary import Diary
from talos.models.topic import Problem
from trans2es.doris.doctor import get_doctor_stat
from trans2es.graph import g
from .es import tzlc, to_epoch
from .transfer import get_area_tag_info, MAX_TIME
from search.utils.area import get_nearby_city_tag_ids


def get_advertise_info(d):
    """ a tuple of (advertise_position, advertise_searchwords, advertise_info)
    """
    # 只选出未过期的广告
    now = timezone.now()
    ad_positions = set()
    ad_searchwords = set()
    ad_tag_ids = set()
    ad_info = []
    ads = AdvertiseManagement.objects.filter(
        doctor=d, is_online=True, end_time__gt=now)
    for ad in ads:
        show_positions = set(ad.get_show_position)
        ad_positions.update(show_positions)
        if ADVER_MANAGEMENT_POSITION_TYPE.SREACH_RESULT in show_positions:
            ad_searchwords.update(set(ad.get_search_words))
        ad_info.append({
            'id': ad.id,
            'position': list(show_positions),
            'start_time_epoch': to_epoch(tzlc(ad.start_time)),
            'end_time_epoch': to_epoch(tzlc(ad.end_time) if ad.end_time else MAX_TIME),
            'searchwords': ad.get_search_words,
            'ordering': ad.ordering,
        })
        ad_tag_ids.update([t.id for t in ad.tags.all()])
    return (list(ad_positions), list(ad_searchwords), ad_info, list(ad_tag_ids))


def get_doctor(instance):
    d = instance

    res = {
        'id': d.id,
        'name': d.name,
        'name_raw': d.name,
        'is_online': d.is_online,
        'is_recommend': d.is_recommend,
        'accept_private_msg': d.accept_private_msg,
        'is_authenticated': True if d.phone else False,
        'doctor_type': d.doctor_type,
        'famous_doctor': d.big,
    }

    # sink
    tickets_result = getattr(d, 'ticketsresult', None)
    if tickets_result:
        res['ticket_sink_start_time'] = tzlc(tickets_result.start_sink)
        res['ticket_sink_end_time'] = tzlc(tickets_result.end_sink)

    # hospital info
    if d.hospital:
        res['hospital'] = {
            'id': d.hospital.id,
            'name': d.hospital.name,
            'hospital_type': d.hospital.hospital_type,
        }
        res['hospital']['name'] = d.hospital.name

        hospital_doctors = Doctor.objects.filter(doctor_type=DOCTOR_TYPE.DOCTOR, hospital=d.hospital, is_online=True)
        res['hospital']['doctor_names'] = list(hospital_doctors.values_list('name', flat=True))
        # hospital position info
        if d.hospital.city:
            h = res['hospital']
            h['city_name'] = d.hospital.city.name
            h['city_province_name'] = d.hospital.city.province.name
            h.update(get_area_tag_info(d.hospital.city))
        if d.hospital.officer:
            h = res['hospital']
            h['officer_name'] = d.hospital.officer.name

    # problem info
    res['problems'] = []
    problems = Problem.objects.prefetch_related('problemtag_set').filter(is_online=True, user_id=d.user_id)

    for p in problems:
        res['problems'].append({
            'id': p.id,
            'tags': [t.name for t in Tag.objects.filter(id__in=[pt.tag_id for pt in p.problemtag_set.all()])]
        })
    last_update_time = d.last_answered_time
    res['last_update_time'] = tzlc(last_update_time)

    # service info
    res['services'] = [{
        'id': s.id,
        'name': s.name,
        'short_description': s.short_description,
        'start_time': tzlc(s.start_time),
        'end_time': tzlc(s.end_time) if s.end_time else MAX_TIME,
        'special_ids': s.get_can_sell_item_ids_and_current_special_id().values()
    } for s in d.services.filter(is_online=True)]
    if res['services']:
        res['has_service'] = True
    else:
        res['has_service'] = False

    # bodypart tags
    bodypart_tags = d.tags.filter(tag_type=TAG_TYPE.BODY_PART, is_online=True)
    res['bodypart_tags'] = [bp.name for bp in bodypart_tags]
    # bodypart subitem tag
    bodypart_subitem_tags = d.tags.filter(tag_type=TAG_TYPE.BODY_PART_SUB_ITEM, is_online=True)
    res['bodypart_subitem_tags'] = [bp_si.name for bp_si in bodypart_subitem_tags]
    # closure_tags
    closure_tags = TagControl.get_ancestors(
        initial_set=d.tags.filter(is_online=True),
        exclude_init=False,
        is_online_only=True)

    # 添加公立／私立TAG
    tag_id = None
    try:
        tag_id = settings.PUBLIC_TAG_ID if d.hospital.hospital_type == HOSPITAL_TYPE.PUBLIC else settings.PRIVATE_TAG_ID
        closure_tags.append(
            Tag.objects.get(pk=tag_id)
        )
    except AttributeError:
        # 医生未关联Hospital
        pass

    # 添加地域TAG
    try:
        closure_tags.append(
            Tag.objects.get(pk=d.hospital.city.tag_id)
        )
    except (Tag.DoesNotExist, AttributeError):
        pass

    res['closure_tag_ids'] = [t.id for t in closure_tags]

    service_tag_ids = None
    if d.doctor_type == DOCTOR_TYPE.DOCTOR:
        service_tag_ids = ServiceTag.objects.filter(
            service__doctor=d, service__is_online=True).values_list('tag_id', flat=True)
    elif d.hospital:
        service_tag_ids = ServiceTag.objects.filter(
            service__doctor__hospital=d.hospital, service__is_online=True).values_list('tag_id', flat=True)
    if service_tag_ids is not None:
        service_tags = Tag.objects.filter(
            pk__in=service_tag_ids,
            tag_type__in=[TAG_TYPE.BODY_PART, TAG_TYPE.BODY_PART_SUB_ITEM, TAG_TYPE.ITEM_WIKI])
        service_tags = TagControl.get_ancestors(
            initial_set=service_tags,
            exclude_init=False,
            is_online_only=True)
        res['service_closure_tag_ids'] = [t.id for t in service_tags]
        res['service_closure_tags'] = [t.name for t in service_tags]
    else:
        res['service_closure_tag_ids'] = []
        res['service_closure_tags'] = []

    try:
        private_or_public_tag = Tag.objects.get(pk=tag_id)
        res['service_closure_tag_ids'].append(private_or_public_tag.id)
        res['service_closure_tags'].append(private_or_public_tag.name)
    except Tag.DoesNotExist:
        pass

    res['has_diary'] = False
    res['diary_count_over_thres'] = False
    diary_count = 0
    online_diary_set = Diary.objects.filter(is_online=True, doctor_id=d.id)
    for diary in online_diary_set:
        if diary.topics.filter(is_online=True).count() > 0:  # 日记本关联日记帖必须至少有一个上线
            diary_count += 1
            res['has_diary'] = True
            if diary_count >= 10:
                res['diary_count_over_thres'] = True
                break

    # http://bug.gengmei.cc/index.php?m=story&f=view&storyID=125
    # 医生 关联的 所有 上线的日记本 关联的 所有 类型属于 {一级分类、二级分类、三级分类} 的 Tag 的名字
    diary_tag_names = set()
    for diary in online_diary_set:
        if d.is_online:
            diary_tag_names.update(map(
                lambda tag: tag.name,
                filter(
                    lambda tag: tag.tag_type in [
                        TAG_TYPE.BODY_PART,
                        TAG_TYPE.BODY_PART_SUB_ITEM,
                        TAG_TYPE.ITEM_WIKI
                    ],
                    diary.tags
                )
            ))
    res['diary_tag_names'] = list(diary_tag_names)

    res['msg_last_update_time'] = res['last_update_time']
    if d.user_id:
        msg_last_update_time = Message.objects.filter(user_id=d.user.id).order_by('-send_time').first()
        if msg_last_update_time is not None:
            res['msg_last_update_time'] = max(res['msg_last_update_time'], tzlc(msg_last_update_time.send_time))

    # 广告信息
    res['advertise_position'], res['advertise_searchwords'], res['advertise_info'], res['advertise_tag_ids'] = \
        get_advertise_info(d)

    # 案例数
    res['share_diary_num'] = d.share_diary_num

    # 美购数
    res['services_num'] = len(res['services'])

    # 互动贡献
    last_recommend_answer = Answer.objects.filter(
        user=d.user,
        is_recommend=True,
    ).order_by('create_time').last()
    res['last_recommend_answer_epoch'] = to_epoch(
        tzlc(last_recommend_answer.create_time)) if last_recommend_answer else 0

    # 评价指数
    res['effect_rating'] = d.effect_rating
    res['attitude_rating'] = d.attitude_rating
    res['env_rating'] = d.env_rating

    doris_data = get_doctor_stat(d.id)
    # {"last_30d_payment": 0.0, "last_30d_ad_money": 0.0, "ctr": 0.0, "last_30d_uv": 0.0}
    res['last_30d_payment'] = doris_data.get('last_30d_payment', 0.0)
    res['last_30d_ad_money'] = doris_data.get('last_30d_ad_money', 0.0)
    res['ctr'] = doris_data.get('ctr', 0.0)
    res['last_30d_uv'] = doris_data.get('last_30d_uv', 0.0)
    res['xiadan_index'] = doris_data.get('xiadan_index', 0.0)

    punishment = Punishment.get_punishment_by_doctor_id(d.id).get('doctor', None)
    if punishment and punishment.get('type', None) in ['limit', ]:
        res['org_sink_start_time'] = tzlc(punishment['start_time'])
        res['org_sink_end_time'] = tzlc(punishment['end_time'])

    # 排序得分 = 咨询因子开根号 * ctr开根号*（单pv佣金贡献+0.7*单pv的CPT消耗）
    res['rank_score'] = DoctorRankFactor.get_rank_score(instance.id)

    # 医生临近城市
    try:
        res['nearby_city_tag_ids'] = get_nearby_city_tag_ids(d.hospital.city.id)
    except (AttributeError, KeyError):
        res['nearby_city_tag_ids'] = []

    try:
        res['merchant_id'] = MerchantRelevance.objects.get(doctor_id=d.id).merchant_id
    except MerchantRelevance.DoesNotExist:
        res['merchant_id'] = None
    return res
