# coding: utf-8
from django.db import transaction, IntegrityError
from django.db.models import F
from gm_types.gaia import DOCTOR_TYPE

from api import Service
from hippo.models import DoctorServiceRank, DoctorDiaryRank, Doctor
from hippo.tool.user_tool import get_doctor_from_context
from hippo.utils import has_add_service_rank_permission, \
    has_delete_service_rank_permission
from rpc.decorators import bind_context, bind
from rpc.tool.error_code import CODES, gen
from talos import Diary


@bind('doctor/service/rank/list')
def doctor_service_rank_list(doctor_id, service_ids):
    """通过doctor_id 和美购IDS获取排名信息

    :param str doctor_id: 医生或机构ID
    :param service_ids: 美购IDS
    :return: List[Dict]
    """
    doctor_service_ranks = DoctorServiceRank.objects.filter(doctor_id=doctor_id, service_id__in=service_ids)
    return {_.service_id: _.rank for _ in doctor_service_ranks}


@bind('doctor/diary/rank/list')
def doctor_diary_rank_list(doctor_id, diary_ids):
    """通过doctor_id 和日记本IDS获取排名信息

    :param str doctor_id: 医生或机构ID
    :param diary_ids: 日记本IDS
    :return: List[Dict]
    """
    doctor_diary_ranks = DoctorDiaryRank.objects.filter(doctor_id=doctor_id, diary_id__in=diary_ids)
    return {_.diary_id: _.rank for _ in doctor_diary_ranks}


@bind('doctor/service/rank/add')
def doctor_service_rank_add(doctor_id, service_id, rank):
    """医生或者机构美购排序
    获取当前操作用户和添加的医生是为了以后机构可以修改医生的美购

    :param doctor_id: 医生或者机构ID
    :param service_id: 美购ID
    :param rank: 排名
    """
    if rank <= 0:
        gen(CODES.RANK_ERROR)

    doctor = Doctor.objects.filter(id=doctor_id, is_online=True).first()
    if not doctor:
        gen(CODES.DOCTOR_NOT_FOUND)

    service = Service.objects.filter(id=service_id, is_online=True).first()
    if not service:
        gen(CODES.SERVICE_NOT_EXSIT)

    result = DoctorServiceRank.get_cmp_max_rank_result(doctor, rank)

    with transaction.atomic():
        if result <= 0:
            DoctorServiceRank.objects.filter(
                doctor=doctor, rank__gte=rank
            ).update(rank=F('rank') + 1)
            result = 1  # 如果插入的是中间位置, 则result = 1, 插入位置为给定的位置, 其余的都往后移
        try:
            DoctorServiceRank.objects.create(doctor=doctor, service_id=service_id, rank=(rank + 1 - result))
        except IntegrityError:
            gen(CODES.SERVICE_RANK_EXIST)


@bind('doctor/service/rank/delete')
def doctor_service_rank_delete(service_id, doctor_id):
    """取消美购的排序 获取当前操作用户和添加的医生是为了以后机构可以修改医生的美购

    :param service_id: 美购ID
    :param doctor_id: 医生或者机构ID, 如果为空则是美购下架
    :return:
    """
    service = Service.objects.filter(id=service_id).first()
    if not service:
        gen(CODES.SERVICE_NOT_EXSIT)

    doctor_service_ranks = DoctorServiceRank.objects.filter(service_id=service_id, doctor_id=doctor_id)

    if not doctor_service_ranks:
        gen(CODES.SERVICE_RANK_NOT_EXSIT)

    with transaction.atomic():
        DoctorServiceRank.batch_delete_rank(doctor_service_ranks)


@bind('doctor/service/rank/batch_delete')
def doctor_service_rank_batch_delete(doctor_id=None, service_id=None):
    """下线医生批量删除美购排序的数据

    :param string doctor_id: 医生或者机构ID, 如果为空则是日记本下架
    :param int service_id: 美购ID
    """
    if doctor_id:
        doctor = Doctor.objects.get(id=doctor_id)
        # 机构管理者的暂时不处理
        if doctor.doctor_type == DOCTOR_TYPE.OFFICER:
            return

        # 获取删除医生的所有美购
        service_ids = Service.objects.filter(doctor_id=doctor_id).values_list('id', flat=True)

        doctor_diary_ranks = DoctorServiceRank.objects.filter(
            service_id__in=list(service_ids)
        )
    elif service_id:
        doctor_diary_ranks = DoctorServiceRank.objects.filter(service_id=service_id)
    else:
        return
    with transaction.atomic():
        DoctorServiceRank.batch_delete_rank(doctor_diary_ranks)


@bind('doctor/diary/rank/add')
def doctor_diary_rank_add(doctor_id, diary_id, rank):
    """医生或者机构日记本排序

    :param string doctor_id: 医生或者机构ID
    :param int diary_id: 日记本ID
    :param int rank: 排名
    """
    if rank <= 0:
        gen(CODES.RANK_ERROR)

    doctor = Doctor.objects.filter(id=doctor_id, is_online=True).first()
    if not doctor:
        gen(CODES.DOCTOR_NOT_FOUND)

    diary = Diary.objects.filter(id=diary_id, is_online=True).first()
    if not diary:
        gen(CODES.DIARY_NOT_FOUND)

    result = DoctorDiaryRank.get_cmp_max_rank_result(doctor, rank)
    with transaction.atomic():
        if result <= 0:
            DoctorDiaryRank.objects.filter(
                doctor=doctor, rank__gte=rank
            ).update(rank=F('rank') + 1)
            result = 1  # 如果插入的是中间位置, 则result = 1, 插入位置为给定的位置, 其余的都往后移
        try:
            DoctorDiaryRank.objects.create(doctor=doctor, diary_id=diary_id, rank=(rank + 1 - result))
        except IntegrityError:
            gen(CODES.DIARY_RANK_EXIST)


@bind('doctor/diary/rank/delete')
def doctor_diary_rank_delete(diary_id, doctor_id):
    """取消日记本的排序

    :param int diary_id: 日记本ID
    :param string doctor_id: 医生或者机构ID, 如果为空则是日记本下架
    :return:
    """
    diary = Diary.objects.filter(id=diary_id).first()
    if not diary:
        gen(CODES.DIARY_NOT_FOUND)

    doctor_diary_ranks = DoctorDiaryRank.objects.filter(diary_id=diary_id, doctor_id=doctor_id)
    if not doctor_diary_ranks:
        gen(CODES.DIARY_RANK_NOT_FOUND)
    DoctorDiaryRank.batch_delete_rank(doctor_diary_ranks)


@bind('doctor/diary/rank/batch_delete')
def doctor_diary_rank_batch_delete(doctor_id=None, diary_id=None):
    """下线医生批量删除日记本排序的数据

    :param string doctor_id: 医生或者机构ID, 如果为空则是日记本下架
    :param int diary_id: 日记本ID
    """
    if doctor_id:
        doctor = Doctor.objects.get(id=doctor_id)

        # 机构管理者的暂时不处理
        if doctor.doctor_type == DOCTOR_TYPE.OFFICER:
            return

        # 获取当前医生所有日记本
        diary_ids = Diary.objects.filter(doctor_id=doctor_id).values_list('id', flat=True)

        doctor_diary_ranks = DoctorDiaryRank.objects.filter(diary_id__in=list(diary_ids))
    elif diary_id:
        doctor_diary_ranks = DoctorDiaryRank.objects.filter(diary_id=diary_id)
    else:
        return
    with transaction.atomic():
        DoctorDiaryRank.batch_delete_rank(doctor_diary_ranks)
