# coding=utf-8

from django.core import serializers
from django.db import transaction
from django.db.models import Count, F
from gm_types.error import ERROR
from gm_types.gaia import DOCTOR_TYPE, SERVICE_FLAG

from hippo.models import Doctor
from lasker.models import Award, Participant, Vote, Lasker
from lasker.tasks import forge_vote
from rpc.decorators import bind, cache_page
from rpc.tool.error_code import gen


@bind('api/lasker/vote')
def lasker_vote(award_id, doctor_id, wx_uid):
    """
    名医大赏：投票接口
    :param award_id:
    :param doctor_id:
    :param wx_uid:
    :return:
    """
    with transaction.atomic():
        try:
            participant = Participant.objects.select_for_update().get(award_id=award_id, doctor_id=doctor_id)
        except Participant.DoesNotExist:
            return gen(ERROR.DOCTOR_NOT_PARTICIPANT)

        if Vote.has_vote_qualify(wx_uid, participant.id):
            # 增加事物操作
            Vote.objects.create(wx_uid=wx_uid, participant_id=participant.id)
            participant.votes_num += 1
            participant.save(update_fields=["votes_num"])
        else:
            return gen(ERROR.EXCEED_VOTE_LIMIT)

    forge_vote.apply_async(countdown=5 * 60, kwargs={'participant_id': participant.id})
    return gen(ERROR.SUCCESS)


@bind('api/lasker/participant')
def lasker_participant(doctor_id, award_ids):
    """
    名医大赏：报名接口
    :param doctor_id:
    :param award_ids:
    :return:
    """
    doctor = Doctor.objects.only('id', 'doctor_type').filter(id=doctor_id).first()
    if not doctor:
        gen(ERROR.DOCTOR_NOT_FOUND)

    if doctor.doctor_type == DOCTOR_TYPE.DOCTOR:
        laureate_type = SERVICE_FLAG.DOCTOR
    else:
        laureate_type = SERVICE_FLAG.HOSPITAL
    awards = Award.objects.filter(id__in=award_ids, laureate_type=laureate_type).all()
    if len(awards) != len(award_ids):
        gen(ERROR.UNIVERSAL)
    for award_id in award_ids:
        try:
            Participant.objects.create(doctor_id=doctor_id, award_id=award_id)
        except (Award.DoesNotExist,):
            pass

    return gen(ERROR.SUCCESS)


@bind('api/lasker/participant_detail')
def lasker_participant_detail(doctor_id, wx_uid=None):
    """
    名医大赏：报名详情
    :param wx_uid:
    :param doctor_id:
    :return:
    """
    lasker = Lasker.objects.get(year=2018, name=u'金刀奖')
    data = []
    participants = Participant.objects.prefetch_related('award').filter(doctor_id=doctor_id, award__lasker=lasker).all()
    for participant in participants:
        current_participant_votes_num = participant.votes_num
        previous_persons = Participant.objects.filter(
            award=participant.award, votes_num__gt=current_participant_votes_num
        ).order_by("votes_num").values_list("votes_num", flat=True)
        prev_votes_num = previous_persons[0] if previous_persons else 0

        ranking = previous_persons.count() + 1

        data.append({
            'id': participant.award.id,
            'name': participant.award.name,
            'image': participant.award.image,
            'votes_num': participant.votes_num if participant else 0,
            # 'is_voted': Vote.has_vote_qualify(wx_uid=wx_uid, participant_id=participant.id)
            # if participant and wx_uid else False,
            'is_voted': False,
            'ranking': ranking,
            "prev_votes_num": prev_votes_num,
        })

    return data


@bind('api/lasker/rank')
def lasker_rank(award_id, offset=0, count=100):
    """
    名医大赏：排行榜
    :param award_id:
    :param offset:
    :param count:
    :return:
    """
    queryset = Participant.objects.filter(award_id=award_id).annotate(
        votes=Count('votes')
    ).order_by('-votes')[offset:offset + count]
    return serializers.serialize('python', queryset)


@bind('api/lasker/detail')
def doctor_detail(doctor_id, award_id=None):
    """
    名医大赏：医生详情
    :param doctor_id:
    :param award_id:
    :return:
    """
    queryset = Participant.objects.filter(doctor_id=doctor_id)

    if award_id:
        queryset = queryset.filter(award_id=award_id)
    queryset = queryset.annotate(votes=Count('votes')).order_by('-votes')
    return serializers.serialize('python', queryset)


@bind('api/lasker/awards')
@cache_page(10 * 60)
def get_lasker_awards():
    lasker = Lasker.objects.filter(year=2018, name=u'金刀奖')
    queryset = Award.objects.filter(lasker=lasker)
    data = []
    for award in queryset:
        data.append({
            'id': award.id,
            'image': award.image,
            'image_selected': award.image_styled,
            'name': award.name,
            'laureate_type': award.laureate_type,
        })
    return data


@bind('api/lasker/participated')
def get_participated_doctor(doctor_ids):
    """
    判断医生是否报过名
    :param doctor_ids:
    :return:
    """
    exist_doctor_ids = Participant.objects.filter(
        doctor_id__in=doctor_ids, award__lasker__year=2018, award__lasker__name=u'金刀奖'
    ).values_list('doctor_id', flat=True)
    return list(exist_doctor_ids)
