# -*- coding: UTF-8 -*-
from __future__ import absolute_import

import datetime
import json

from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.db import IntegrityError
from django.db import transaction
from django.db.models import Q
from gm_types.doctor import DOCTOR_REGISTER_STATUS, DOCTOR_INFO_STATUS, DOCTOR_ACCOUNT_STATUS, \
    DOCTOR_TITLE_TYPE, DOCTOR_LICENCE_TYPE, HOSPITAL_MEDICAL_TYPE, HOSPITAL_LEVEL, HOSPITAL_SCALE
from gm_types.gaia import TAG_TYPE, VIDEO_CODE_STATUS

from api.models import Doctor, DoctorTag, Order, ORDER_STATUS, DOCTOR_TYPE, HOSPITAL_TYPE, \
    User, Person, DoctorAccount, DocBusinessRecord, DoctorEditRecord, \
    DoctorAccountRecord, DoctorAgreement
from api.models import POSMachine, POSRecord, POSSum
from api.models import Reservation, RESERVATION_STATUS
from api.models import Tag, DocprojectTag
from api.models.organization import OrganizationImage
from api.tasks.doctor_rank_task import delete_service_rank
from api.tasks.hospital_task import set_water_mark_to_video_hospital
from api.tool.datetime_tool import get_datetime
from api.tool.image_utils import get_full_path, get_short_path
from api.tool.user_tool import get_user_extra_by_user_id, get_user_by_id, generate_random_nick_name
from doctor.models import DoctorRegister
from doctor.models.capture import DoctorRegisterRecord
from hera.queries.doctor import DoctorDQ
from hera.queries.doctorregister import DoctorRegisterDQ
from hera.queries.phoneservice import PhoneServiceDQ
from hera.utils import check_business, reset_username, get_business_team
from hippo.models import Doctor_Extra, HospitalInstrument, HospitalVideo, \
    HospitalRecommendService, HospitalRecommendDoctor, DoctorLicence
from hippo.models import FinanceCity, MerchantAccount, MerchantAccountRecord
from hippo.models import Hospital_Extra, HospitalRestAssured, HospitalSpecialService
from hippo.models import MerchantRelevance, PhoneServiceRecord
from maidan.models import MaidanSetting, Hospital
from rpc.cache import req_data_cache
from rpc.decorators import bind_context
from rpc.exceptions import RPCIntegrityError, RPCNotFoundException
from rpc.tool.dict_mixin import to_dict
from rpc.tool.error_code import gen, CODES
from rpc.tool.log_tool import info_logger, logging_exception
from services.talos_service import diary_filter
from talos.models.diary import Diary
from themis.models import Team
from ..datatables import DoctorDT
from ..models import UserPerm

uri_pre = 'hera/doctor'


@bind_context(uri_pre + '/choices')
def doctor_choices(ctx, q='', page=1, num=30, initial=None, business=None, doctor_id=None, self_run=None,
                   doctor_type=None, special_id=None):
    page = int(page)
    num = int(num)

    if initial is not None:
        if isinstance(initial, (list, tuple)):
            qry = Q(id__in=initial)
        else:
            qry = Q(id=initial)
    else:
        qry = Q(id__contains=q) | Q(name__contains=q)
        qry &= Q(is_online=True)
        qry &= Q(user__isnull=False)
    # 自营医生
    if self_run is not None:
        qry = Q(self_run=True)

    if doctor_type is not None:
        qry &= Q(doctor_type=doctor_type)

    # 关联医生
    if doctor_id:
        try:
            doctor = Doctor.objects.get(id=doctor_id)
            qry &= Q(hospital=doctor.hospital) & ~Q(id=doctor_id)
        except:
            pass

    if business is not None:
        if isinstance(business, (list, tuple)):
            qry &= Q(business_partener_id__in=business)
        else:
            qry &= Q(business_partener_id=business)

    query = Doctor.objects.using(settings.SLAVE_DB_NAME).filter(qry)

    if special_id is not None:
        query = query.filter(services__items__specialitem__special_id=special_id).distinct()

    total_count = query.count()
    start_pos = (page - 1) * num
    start_pos = start_pos if start_pos >= 0 else 0
    results = [
        {
            'id': obj.id,
            'text': u'{}:{}({})({})({})'.format(
                obj.id,
                obj.name,
                obj.hospital.name if hasattr(obj, 'hospital') and obj.hospital else None,
                obj.title if obj.doctor_type == DOCTOR_TYPE.DOCTOR else
                HOSPITAL_TYPE.getDesc(obj.hospital.hospital_type
                                      if hasattr(obj, 'hospital') and obj.hospital else None),
                u'在线' if obj.is_online else u'离线'
            ),

        } for obj in query[start_pos: start_pos + num]
        ]
    return {'total_count': total_count, 'results': results, 'page': page, 'num': num}


@bind_context(uri_pre + '/query')
def doctor_query(ctx, options):
    init_q = None
    _in, businessman_list, team_groups = get_business_team(ctx)
    if _in:
        init_q = Q(business_partener__in=businessman_list) | Q(business_group__in=team_groups)
    dqobj = DoctorDQ(init_q=init_q)
    return dqobj.process(**options)


@bind_context(uri_pre + '/list')
def doctor_datatable(ctx, req_data):
    if check_business(ctx.session.groups):
        # 判断是商务并且非商务leader
        user = ctx.session.user
        members = UserPerm.members(user)
        init_q = Q(business_partener__in=members) | Q(business_partener_id__isnull=True)
    else:
        init_q = None
    dtobj = DoctorDT(Doctor, init_q=init_q)
    return dtobj.process(
        req_data,
        ['name', 'hospital__name', 'business_partener__username', 'hospital__city__name'],
    )


def hospital_info(hospital):
    data = {}
    data['instrument_intro'] = ''
    data['instrument_info'] = []
    data['video_url'] = ''
    data['video_pic'] = ''
    data['recomment_services'] = ''
    data['recomment_doctors'] = ''
    instrument = HospitalInstrument.objects.filter(hospital=hospital).first()
    if instrument:
        data['instrument_intro'] = instrument.intro
        data['instrument_info'] = json.loads(instrument.content or '[]')
    video = HospitalVideo.objects.filter(hospital=hospital).first()
    if video:
        data.update(video.get_video_info())

    r_services = HospitalRecommendService.recomend_services_info(hospital.id)
    r_doctors = HospitalRecommendDoctor.recomend_doctors_info(hospital.id)
    data['recommend_services'] = ','.join([x['name'] for x in r_services])
    data['recommend_doctors'] = ','.join([x['name'] for x in r_doctors])
    return data


@bind_context(uri_pre + '/get')
def doctor_detail(ctx, doctor_id, options=None):
    try:
        doctor = Doctor.objects.get(id=doctor_id)
    except:
        raise RPCNotFoundException
    if options is None:
        options = {
            'fields': None,
            'excludes': None,
            'expands': None,
        }
    doctor_data = to_dict(doctor, **options)

    # 筛选出个性化标签
    tags = doctor_data.get('tags', [])
    commontag = []
    specialtag = []
    if tags:
        for tag_obj in tags:
            service_obj = DoctorTag.objects.get_or_create(
                doctor_id=doctor.id,
                tag=tag_obj)
            tag = Tag.objects.get_or_create(id=service_obj[0].tag_id)
            if tag[0].tag_type == TAG_TYPE.YUNYING:
                specialtag.append(tag_obj)
            else:
                commontag.append(tag_obj)
    doctor_data['specialtag'] = specialtag
    doctor_data['tags'] = commontag

    doctor_data['hospital_id'] = doctor.hospital.id if doctor.hospital else None
    result = diary_filter(filters={'doctor_id': doctor_id}, with_count=True)
    doctor_data['diary_num'] = result.get('total_count', 0)
    doctor_data['service_num'] = doctor.services.count()
    order_query = Order.objects.filter(service__doctor=doctor)
    doctor_data['order_num'] = order_query.count()
    doctor_data['reservation'] = Reservation.objects.filter(schedule__doctor=doctor,
                                                            status=RESERVATION_STATUS.RESERVING).count()
    doctor_data['reservation_expired'] = Reservation.objects.filter(schedule__doctor=doctor,
                                                                    status=RESERVATION_STATUS.EXPIRED).count()

    status_set = (ORDER_STATUS.NOT_PAID, ORDER_STATUS.PAID,
                  ORDER_STATUS.USED, ORDER_STATUS.SETTLED,
                  ORDER_STATUS.AUDITING, ORDER_STATUS.SETTLING,
                  ORDER_STATUS.REFUNDED, ORDER_STATUS.WAIT_REFUNDED)
    doctor_data['place_order_num'] = order_query.filter(status__in=status_set).count()
    status_set = [ORDER_STATUS.REFUNDED, ORDER_STATUS.WAIT_REFUNDED]
    doctor_data['refund_order_num'] = order_query.filter(status__in=status_set).count()
    doctor_data['valid_order_num'] = order_query.filter(validated=True).count()
    doctor_data['start_time_hour'] = "%02d" % doctor.start_time.hour
    doctor_data['start_time_min'] = "%02d" % doctor.start_time.minute
    doctor_data['end_time_hour'] = "%02d" % doctor.end_time.hour
    doctor_data['end_time_min'] = "%02d" % doctor.end_time.minute
    doctor_data['b_licences'] = doctor.b_licences
    doctor_data['p_licences'] = doctor.p_licences
    doctor_data['t_licences'] = doctor.t_licences
    doctor_data['title'] = DOCTOR_TITLE_TYPE.getDesc(doctor_data.get('title', '0'))

    doctor_data['agreement_image'] = doctor.agreement_image
    doctor_data['is_agreement_checked'] = False if doctor.status == DOCTOR_INFO_STATUS.CHECK_PENDING else True
    if getattr(doctor.user, 'person', None):
        doctor_data['area'] = doctor.user.person.area_id or 1
        doctor_data['email'] = doctor.user.person.email or ''
        doctor_data['doctor_login_phone'] = doctor.user.person.phone or ''
    else:
        doctor_data['area'] = 1
        doctor_data['email'] = ''
        doctor_data['doctor_login_phone'] = ''

    if getattr(doctor, 'merchant', None) and doctor.merchant.is_online == True:
        merchant = doctor.merchant
        doctor_data['merchant_id'] = merchant.id
        if getattr(merchant, 'billinfo', None):
            doctor_data['merchant_billinfo_id'] = merchant.billinfo.id
        else:
            doctor_data['merchant_billinfo_id'] = None
    else:
        doctor_data['merchant_id'] = ''
    doctor_data['organization_images'] = []
    # doctor的图片信息
    if doctor_data['doctor_type'] == DOCTOR_TYPE.OFFICER:
        if doctor_data.get('hospital', None) is None:
            for organization_image in OrganizationImage.objects.filter(doctor=doctor):
                doctor_data['organization_images'].append(get_full_path(organization_image.image_url))
        else:
            for organization_image in OrganizationImage.objects.filter(hospital_id=doctor_data['hospital']):
                doctor_data['organization_images'].append(get_full_path(organization_image.image_url))
    # 医生收款信息
    try:
        doctoraccount, _ = DoctorAccount.objects.get_or_create(doctor_id=doctor_id)
    except IntegrityError:
        raise RPCIntegrityError
    doctor_data.update(to_dict(doctoraccount, excludes=['id']))

    doctor_data['project_info'] = []
    for tag in doctor.project_tags.all():
        data = {
            'tag_id': tag.id,
            'tag_name': tag.name
        }
        doctor_data['project_info'].append(data)
    # 医生买单信息
    try:
        setting_data = MaidanSetting.objects.get(doctor_id=doctor_id)
        doctor_data['has_infomation'] = setting_data.is_open
        doctor_data['doctor_discount'] = setting_data.doctor_discount_rate
        doctor_data['gengmei_offers'] = setting_data.gengmei_offers_rate
    except:
        doctor_data['has_infomation'] = False
    doctor_data['hospital_type'] = HOSPITAL_TYPE.getDesc(doctor.hospital.hospital_type) if doctor.hospital else ''
    try:
        doctor_data['login_phone'] = doctor.user.person.phone
    except:
        doctor_data['login_phone'] = ''
    doctor_data['hospital_image'] = doctor.hospital_pics()
    doctor_data['status'] = doctor.status
    # 2017-12-14春琪需求新添加信息
    if doctor.extra_info:
        doctor_data.update(doctor.extra_info)
    doctor_data['personalized_photo_album'] = doctor.personalized_photo_album
    doctor_data['recommend_services'] = ','.join([item['name'] for item in doctor.recommend_services])
    doctor_data['hospital_info'] = hospital_info(doctor.hospital)

    if doctor.doctor_type == DOCTOR_TYPE.OFFICER:
        hospital_extras = Hospital_Extra.objects.filter(hospital_id=doctor.hospital.id)
        # 荣誉图片
        doctor_data.update({
            'honor_pics': doctor.honor_pics
        })
        if hospital_extras.exists():
            hospital_extra = hospital_extras.first()
            doctor_data.update({
                'open_time': str(hospital_extra.open_time)[0:7],
                'hospital_type_desc': HOSPITAL_MEDICAL_TYPE.getDesc(hospital_extra.hospital_type),
                'hospital_type': hospital_extra.hospital_type,
                'level_image': doctor.level_image,
                'business_area': hospital_extra.business_area,
                'notice': hospital_extra.notice,

                'area_image': doctor.area_image,
                'is_inter_province_chain': hospital_extra.is_inter_province_chain,
                'inter_province_chain_hospital_desc': hospital_extra.inter_province_chain_hospital.name if
                hospital_extra.inter_province_chain_hospital else '',
                'inter_p_image': doctor.inter_p_image,
                'is_same_province_chain': hospital_extra.is_same_province_chain,
                'same_province_chain_hospital_desc': hospital_extra.same_province_chain_hospital.name if
                hospital_extra.same_province_chain_hospital else '',
                'same_p_image': doctor.same_p_image,
                # 7680 添加 医院规模参数
                'hospital_scale': hospital_extra.scale,
                # 7725 添加 床位、荣誉图片、介绍
                'honor_introduction': hospital_extra.honor_introduction,
                'bed_count': hospital_extra.bed_count,
                'department_count': hospital_extra.department_count,
                'ad_check_img': hospital_extra.ad_check_img,
                'ad_check_start_time': hospital_extra.ad_check_start_time.strftime('%Y-%m-%d')
                if hospital_extra.ad_check_start_time else '',
                'ad_check_end_time': hospital_extra.ad_check_end_time.strftime('%Y-%m-%d')
                if hospital_extra.ad_check_end_time else '',
                'practice_start_time': hospital_extra.practice_start_time.strftime('%Y-%m-%d')
                if hospital_extra.practice_start_time else '',
                'practice_end_time': hospital_extra.practice_end_time.strftime('%Y-%m-%d')
                if hospital_extra.practice_end_time else ''
            })
            if hospital_extra.hospital_type == HOSPITAL_MEDICAL_TYPE.MEDICAL_BEAUTY_HOSPITAL:
                try:
                    doctor_data['hospital_level_desc'] = HOSPITAL_LEVEL.getDesc(hospital_extra.hospital_level)
                except:
                    pass
        # 放心购, HospitalRestAssure
        hospital_rest_assured = HospitalRestAssured.objects.filter(hospital_id=doctor.hospital.id)
        if hospital_rest_assured.exists():
            hospital_rest_assured = hospital_rest_assured.first()
            doctor_data.update({
                'escort': hospital_rest_assured.escort,
                'one_to_one_consulation': hospital_rest_assured.one_to_one_consulation,
                'regular_return_visit': hospital_rest_assured.regular_return_visit
            })


        # 特色服务, HospitalSpecialService
        hospital_special_service = HospitalSpecialService.objects.filter(hospital_id=doctor.hospital.id)
        if hospital_special_service.exists():
            hospital_special_service = hospital_special_service.first()
            doctor_data.update({
                'wifi': hospital_special_service.wifi,
                'paid_parking': hospital_special_service.paid_parking,
                'independent_treatment_room': hospital_special_service.independent_treatment_room,
                'dressing_room': hospital_special_service.dressing_room,
                'free_parking_space': hospital_special_service.free_parking_space,
                'smoking_room': hospital_special_service.smoking_room,
                'free_drink': hospital_special_service.free_drink,
                'free_snack': hospital_special_service.free_snack,
                'swip': hospital_special_service.swip
            })

    return doctor_data


def sync_doctor_name_to_user(doctor, old_name, new_name):
    if new_name == old_name:
        return
    if not new_name:
        name = generate_random_nick_name()
    else:
        name = new_name
        is_doctor = doctor.doctor_type == DOCTOR_TYPE.DOCTOR
        is_suozhang = doctor.user.id == 22
        if is_doctor and not is_suozhang:
            name = u'{} 医生'.format(name)
    info_logger.info(u'医生改名: (%s)[%s] -> [%s]' % (doctor.id, old_name, new_name))
    user = doctor.user
    user.last_name = name
    user.save(update_fields=['last_name'])


@bind_context(uri_pre + '/edit')
@transaction.atomic
def doctor_edit(ctx, doctor_id=None, doctor_info=None):
    user = ctx.session.user
    if doctor_info is None:
        return None
    area_id = doctor_info.pop('area')
    tags = doctor_info.pop('tags', [])
    urls = doctor_info.pop('urls', [])
    related_doctor = doctor_info.pop('related_doctor', [])
    doctor_info['user_id'] = doctor_info.pop('user')
    doctor_info['hospital_id'] = doctor_info.pop('hospital')
    doctor_info['business_partener_id'] = doctor_info.pop('business_partener')
    doctor_info['start_time'] = doctor_info.pop('start_time_hour') + u':' + doctor_info.pop('start_time_min')
    doctor_info['end_time'] = doctor_info.pop('end_time_hour') + u':' + doctor_info.pop('end_time_min')

    doctoraccount_info = {
        'doctor_id': doctor_info.pop('doctor'),
        'province_id': doctor_info.pop('province'),
        'city_id': doctor_info.pop('city'),
        'country_id': doctor_info.pop('country'),
        'bank': doctor_info.pop('bank'),
        'account_name': doctor_info.pop('account_name'),
        'account_number': doctor_info.pop('account_number'),
        'account_type': doctor_info.pop('account_type')
    }

    doctors = Doctor.objects.filter(
        doctor_type=DOCTOR_TYPE.OFFICER,
        hospital_id=doctor_info['hospital_id'],
    ).exclude(
        id=doctor_id,
    )
    if doctors.exists() and doctor_info['doctor_type'] == DOCTOR_TYPE.OFFICER:
        # 已存在一个机构管理者
        return gen(CODES.HOSPITAL_HAD_OFFICER)

    need_register_400 = False
    doctor_phone = doctor_info.get('phone', None)

    if doctor_id is None:
        old_name = ''
        try:
            doctor = Doctor.objects.create(**doctor_info)
            maidan_setting = MaidanSetting.objects.create(
                doctor_id=doctor.id,
                is_open=True,
            )
            need_register_400 = True
            try:
                docrecord = DocBusinessRecord()
                docrecord.doctor_id = doctor.id
                docrecord.to_business_id = doctor_info.get('business_partener_id', '')
                docrecord.user = user
                docrecord.save()
            except:
                pass
        except IntegrityError:
            raise RPCIntegrityError
    else:
        try:
            doctor = Doctor.objects.get(id=doctor_id)
        except:
            info_logger.info(__import__('traceback').format_exc())
            raise RPCNotFoundException
        old_name = doctor.name
        if doctor.phone != doctor_info.get('phone', ''):
            # 新的医生手机号与原手机号不一致
            need_register_400 = True
        # if doctor.hospital is None and doctor.doctor_type == DOCTOR_TYPE.OFFICER:
        #     # 原来的医生关联的机构为空
        #     OrganizationImage.objects.filter(doctor_id=doctor_id).update(hospital_id=doctor.hospital.id)
        # 机构上传图片
        business_partener_id = int(doctor.business_partener_id) if doctor.business_partener else None
        now_business = doctor_info.get('business_partener_id', None)
        to_business_partener_id = int(now_business) if now_business else None
        if business_partener_id != to_business_partener_id:
            try:
                docrecord = DocBusinessRecord()
                docrecord.doctor_id = doctor.id
                docrecord.business_id = business_partener_id
                docrecord.to_business_id = doctor_info.get('business_partener_id', '')
                docrecord.user = user
                docrecord.save()
            except:
                pass
        if doctor_info['doctor_type'] == DOCTOR_TYPE.OFFICER:
            org_image = OrganizationImage.objects.filter(hospital_id=doctor_info['hospital_id'])
            short_urls = []
            for url in urls:
                short_urls.append(get_short_path(url))
            if short_urls:
                for url in short_urls:
                    if url:  # url为空则无操作
                        OrganizationImage.objects.get_or_create(doctor=doctor, image_url=url,
                                                                hospital_id=doctor_info['hospital_id'])
                        # 删除删除掉的条目
            org_image.filter(~Q(image_url__in=short_urls)).delete()
        for k, v in doctor_info.iteritems():
            setattr(doctor, k, v)
        doctor.save()

    if need_register_400 and doctor_phone:
        # 注册医生手机号到400服务商
        doctor.register_phone_ext()

    # update doctor info into user
    try:
        user_id = doctor_info['user_id']
        user = get_user_by_id(user_id)
        extra = get_user_extra_by_user_id(user.id)
    except:
        user = None
        extra = None
    if extra and doctor.portrait:
        extra.portrait = doctor.portrait
        extra.last_login = datetime.datetime.now()
        extra.save()
    sync_doctor_name_to_user(doctor, old_name, doctor.name)
    if user_id:
        person = Person.objects.get(user_id=user_id)
        person.area_id = area_id
        person.save()
    if tags:
        new_tags = set(Tag.objects.filter(id__in=tags))
        old_tags = set(doctor.tags.all())
        for tag_obj in (new_tags - old_tags):
            DoctorTag.objects.get_or_create(doctor_id=doctor.id, tag=tag_obj)
        DoctorTag.objects.filter(
            doctor_id=doctor.id, tag__in=(old_tags - new_tags),
        ).delete()

    # 关联医生
    new_docs = set(Doctor.objects.filter(id__in=related_doctor))
    old_docs = set(doctor.related_doctor.all())
    doctor.related_doctor.add(*(new_docs - old_docs))
    doctor.related_doctor.remove(*(old_docs - new_docs))
    doctor.save()

    # # 机构上传图片
    # org_image = OrganizationImage.objects.filter(doctor=doctor)
    # short_urls = []
    # for url in urls:
    #     short_urls.append(get_short_path(url))
    # if short_urls:
    #     for url in short_urls:
    #         if url:  # url为空则无操作
    #             OrganizationImage.objects.get_or_create(doctor=doctor, image_url=url,
    #                                                     hospital_id=doctor_info['hospital_id'])
    #             # 删除删除掉的条目
    # org_image.filter(~Q(image_url__in=short_urls)).delete()

    # 医生收款信息
    try:
        doctoraccount, _ = DoctorAccount.objects.get_or_create(doctor_id=doctor.id)
    except IntegrityError:
        raise RPCIntegrityError
    if doctoraccount_info.get('doctor_id'):
        for k, v in doctoraccount_info.iteritems():
            setattr(doctoraccount, k, v)
        doctoraccount.save()

    return doctor.id


@bind_context(uri_pre + '/online_update')
def online_update(ctx, items):
    threshold_dt = datetime.datetime(2010, 1, 1)
    info = []
    for obj in items:
        doctor = Doctor.objects.get(id=obj['key'])
        doctor.is_online = obj['is_online']
        if doctor.is_online and (not doctor.online_time or doctor.online_time < threshold_dt):
            doctor.online_time = datetime.datetime.now()
        doctor.save()
        info.append(obj['key'])
    return info


@bind_context(uri_pre + '/reset_phone')
@transaction.atomic
def reset_phone(ctx, id, phone, area):
    if area != '+86':
        phone = '{}{}'.format(area, phone)
    if Person.objects.filter(phone=phone).count() == 0:
        try:
            doctor = Doctor.objects.get(id=id)
        except Doctor.DoesNotExist:
            return {'msg': u'用户不存在'}
        user = doctor.user
        if user:
            reset_username(user)
            user.person.phone = phone
            user.userextra.phone = phone
            user.person.save()
            user.userextra.save()
            return {'msg': u'重置成功'}
        else:
            return {'msg': u'医生没有关联用户'}
    else:
        return {'msg': u'重置失败！此手机号已被别的医生／机构绑定，请更换新的手机号或找运营人员帮忙解绑手机号'}


@bind_context(uri_pre + '/account_get')
def doctor_detail(ctx, doctor_id, options=None):
    doctoraccount, _ = DoctorAccount.objects.get_or_create(doctor_id=doctor_id)
    if options is None:
        options = {
            'fields': None,
            'excludes': None,
            'expands': None,
        }
    doctoraccount_data = to_dict(doctoraccount, **options)
    return doctoraccount_data


@bind_context(uri_pre + '/account_edit')
def doctor_edit(ctx, doctor_id=None, doctoraccount_info=None):
    if doctoraccount_info is None:
        return None

    doctoraccount_info['doctor_id'] = doctoraccount_info.pop('doctor')
    doctoraccount_info['province_id'] = doctoraccount_info.pop('province')
    doctoraccount_info['city_id'] = doctoraccount_info.pop('city')
    doctoraccount_info['country_id'] = doctoraccount_info.pop('country')
    try:
        doctoraccount, _ = DoctorAccount.objects.get_or_create(doctor_id=doctor_id)
    except IntegrityError:
        raise RPCIntegrityError
    for k, v in doctoraccount_info.iteritems():
        setattr(doctoraccount, k, v)
    doctoraccount.save()


@bind_context(uri_pre + '/project_edit')
def doctor_project_edit(ctx, doctor_id=None, projects_ids=None):
    if projects_ids is None:
        return None

    has_projects = DocprojectTag.objects.filter(doctor_id=doctor_id)
    for has_project in has_projects:
        if has_project.id in projects_ids:
            projects_ids.pop(has_project.id)
            continue
        has_project.delete()

    for project_id in projects_ids:
        new_project = DocprojectTag.objects.create(doctor_id=doctor_id, tag_id=project_id)
        new_project.save()


@bind_context(uri_pre + '/get_project')
def doctor_project_edit(ctx, doctor_id, tag_id, options=None):
    try:
        doctor_project = DocprojectTag.objects.get(doctor_id=doctor_id, tag_id=tag_id)
    except:
        raise RPCNotFoundException
    if options is None:
        options = {
            'fields': None,
            'excludes': None,
            'expands': None,
        }
    doctor_project_data = to_dict(doctor_project, **options)
    doctor_project_data['diary_data'] = []
    diarys = Diary.objects.filter(
        doctor__id=doctor_id, tags__id=tag_id, is_choice=True)
    for diary in diarys:
        data = {
            'id': diary.id,
            'name': diary.title,
            'content': diary.is_choice_content
        }
        doctor_project_data['diary_data'].append(data)
    return doctor_project_data


@bind_context(uri_pre + '/project_diary_edit')
def doctor_project_diary_edit(ctx, doctor_id=None, tag_id=None, diary_date=None):
    if doctor_id and tag_id and diary_date is None:
        return None
    project = DocprojectTag.objects.get(doctor__id=doctor_id, tag__id=tag_id)
    project.tag_content = diary_date.pop('tag_content')
    new_projects = diary_date.pop('project_diary')
    old_projects = Diary.objects.filter(doctor__id=doctor_id, is_choice=True, tags__id=tag_id)

    for old_project in old_projects:
        old_project.is_choice = False
        old_project.save()

    for new_project in new_projects:
        diary_id = new_project['diary_id']
        diary_content = new_project['diary_content']
        choice_diary = Diary.objects.get(id=diary_id)
        choice_diary.is_choice = True
        choice_diary.is_choice_content = diary_content
        choice_diary.save()
    project.save()
    return project.id


@bind_context(uri_pre + '/voice_query')
def doctor_voice_query(ctx, options):
    req_data_cache.set(ctx.session.session_key + 'phoneservice', json.dumps(options))
    dqobj = PhoneServiceDQ()
    return dqobj.process(**options)


@transaction.atomic
@bind_context(uri_pre + '/business_doctor')
def business_doctor(ctx, business_id, to_business_id):
    doctor_list = []
    user = ctx.session.user
    try:
        doctors = Doctor.objects.filter(business_partener=business_id)
        business = User.objects.get(id=business_id)
        business_name = business.username if not business.last_name or '***' in business.last_name \
            else business.last_name
        to_business = User.objects.get(id=to_business_id)
        to_business_name = to_business.username if not to_business.last_name or '***' in to_business.last_name \
            else to_business.last_name
    except:
        raise RPCNotFoundException
    for doctor in doctors:
        try:
            docrecord = DocBusinessRecord()
            docrecord.doctor_id = doctor.id
            docrecord.business_id = business_id
            docrecord.to_business_id = to_business_id
            docrecord.user = user
            docrecord.save()
        except:
            pass
        doctor_list.append(doctor.id)
        doctor.business_partener_id = to_business_id
        doctor.save()
    data_info = {
        'doctor_list': doctor_list,
        'business': business_name,
        'to_business': to_business_name
    }
    return data_info


@bind_context(uri_pre + '/register/query')
def doctor_register_query(ctx, options):
    """
    医生(医院)注册申请列表页查询
    :param ctx:
    :param options:
    :return:
    """
    dqobj = DoctorRegisterDQ(init_q=Q(status__in=[1, 2, 3, 5]))
    return dqobj.process(**options)


@bind_context(uri_pre + '/register/detail')
def doctor_register_detail(ctx, register_id):
    """
    根据注册ID获取注册信息
    create by oldman at 2017-02-16
    :param ctx:
    :param register_id: 注册ID
    :return:
    """
    data = {}
    try:
        doctor_register = DoctorRegister.objects.get(id=register_id)
        doctor_register_record = DoctorRegisterRecord.objects.filter(doctor_register_id=register_id).last()
    except Exception as e:
        logging_exception()
        raise RPCNotFoundException
    return doctor_register.get_detail_info(), doctor_register_record.get_detail_info()


@transaction.atomic
@bind_context(uri_pre + '/register/review_result')
def doctor_register_review(ctx, register_id, is_pass, reason=None,
                           hospital_id=None, business_id=None, business_group=None):
    """
    审核医生注册
    create by oldman at 2017-02-17
    :param ctx:
    :param register_id:
    :param is_pass:
    :param reason:
    :return:
    """
    person = ctx.session.user.person
    user = ctx.session.user
    if register_id is None:
        raise ValueError('register_id is None')
    try:
        with transaction.atomic():
            register = DoctorRegister.objects.get(id=register_id)
            registerrecord = DoctorRegisterRecord.objects.create(
                doctor_register_id=register.id,
                handler=ctx.session.user.person,
                created_at=datetime.datetime.now(),
                content='',
                status=DOCTOR_REGISTER_STATUS.DATA_CHECKED if is_pass else DOCTOR_REGISTER_STATUS.DATA_REJECT
            )
            if is_pass:
                register.status = DOCTOR_REGISTER_STATUS.DATA_CHECKED
                register.handler = person
                register.save()
                register = DoctorRegister.objects.get(id=register_id)
                registerrecord = DoctorRegisterRecord.objects.create(doctor_register_id=register.id,
                                                                     content=u'修改医生信息',
                                                                     status=DOCTOR_REGISTER_STATUS.DATA_CHECKED,
                                                                     handler=person)

                register.related_hospital_id = hospital_id
                register.business_partener_id = business_id
                register.business_group = business_group
                register.status = DOCTOR_REGISTER_STATUS.DATA_CHECKED
                registerrecord.status = DOCTOR_REGISTER_STATUS.DATA_CHECKED
                registerrecord.save()
                register.save()
                if register.status != DOCTOR_REGISTER_STATUS.DATA_CHECKED:
                    raise ValueError('医生注册申请状态错误！')
                doctor = register.create_doctor(user)
                register.doctor_id = doctor.id
                try:
                    params = [
                        {'name': register.name}
                    ]
                    ctx.rpc_remote['sms/template/send'](phone=register.person.phone,
                                                        template_id=42,
                                                        params=params).unwrap()
                except:
                    logging_exception()

                try:
                    ctx.rpc_remote['artemis/account/create'](doctor_id=doctor.id).unwrap()
                except:
                    logging_exception()

                register.status = DOCTOR_REGISTER_STATUS.FINISHED
                registerrecord.status = DOCTOR_REGISTER_STATUS.FINISHED
                registerrecord.save()
                register.save()
                from hippo.tool.merchant_tool import update_merchant_doctor_relation
                update_merchant_doctor_relation(doctor)
            else:
                register.status = DOCTOR_REGISTER_STATUS.DATA_REJECT
                register.handler = person
                register.save()
                registerrecord.reject_reason = reason
                registerrecord.handler = person
                registerrecord.save()
    except Exception:
        logging_exception()
        raise


@transaction.atomic
@bind_context(uri_pre + '/register/save')
def doctor_register_review(ctx, register_id, hospital_id, business_id, business_group, is_create):
    """
    保存注册医生信息或者创建医生账号
    create by oldman at 2017-02-19
    :param is_create: 是否创建医生账号
    :param register_id: 医生注册ID
    :param ctx:
    :param hospital_id:医院ID
    :param business_id:关联商务ID
    :param hetong_review:合同是否已审核
    :param hetong_images:合同照片
    :return:
    """
    user = ctx.session.user
    if register_id is None:
        raise ValueError('register_id is None')
    try:
        # 同步医生注册的数据
        with transaction.atomic():
            register = DoctorRegister.objects.get(id=register_id)
            registerrecord = DoctorRegisterRecord.objects.create(doctor_register_id=register.id,
                                                                 content=u'修改医生信息',
                                                                 status=DOCTOR_REGISTER_STATUS.DATA_CHECKED,
                                                                 handler=user.person)

            register.related_hospital_id = hospital_id
            register.business_partener_id = business_id
            register.business_group = business_group
            # register.is_agreement_checked = hetong_review
            # if hetong_review:
            #     register.status = DOCTOR_REGISTER_STATUS.AGREEMENT_CHECKED
            #     registerrecord.status = DOCTOR_REGISTER_STATUS.AGREEMENT_CHECKED
            # else:
            #     register.status = DOCTOR_REGISTER_STATUS.DATA_CHECKED
            #     registerrecord.status = DOCTOR_REGISTER_STATUS.DATA_CHECKED
            register.status = DOCTOR_REGISTER_STATUS.DATA_CHECKED
            registerrecord.status = DOCTOR_REGISTER_STATUS.DATA_CHECKED
            registerrecord.save()
            register.save()
            # aggrement_images_old = set(DoctorRegisterAgreement.objects.filter(doctor_register_id=register_id))
            # aggrement_images_new = set()
            # for image in hetong_images:
            #     aggrement_image = DoctorRegisterAgreement.objects.get_or_create(doctor_register_id=register_id,
            #                                                                     image_url=image
            #                                                                     )[0]
            #     aggrement_images_new.add(aggrement_image)
            # for item in aggrement_images_old - aggrement_images_new:
            #     item.delete()

            # 注册医生
            if is_create:
                if register.status != DOCTOR_REGISTER_STATUS.DATA_CHECKED:
                    raise ValueError('医生注册申请状态错误！')
                doctor = register.create_doctor(user)

                try:
                    params = [
                        {'name': register.name}
                    ]
                    ctx.rpc_remote['sms/template/send'](phone=register.person.phone,
                                                        template_id=42,
                                                        params=params).unwrap()
                except:
                    logging_exception()

                try:
                    ctx.rpc_remote['artemis/account/create'](doctor_id=doctor.id).unwrap()
                except:
                    logging_exception()

                # 注册通过之后，创建了医生，状态是 合同待审状态，等待合同审核
                # 但需要注意的是，合同审核已经和注册没有关系了，这是注册最后一条record
                # 之后医生合同审核通过 同步了 register的状态，没有添加record，目的只是为了PC端展示
                register.status = DOCTOR_REGISTER_STATUS.CHECK_PENDING
                registerrecord.status = DOCTOR_REGISTER_STATUS.CHECK_PENDING
                registerrecord.save()
                register.save()
    except Exception:
        logging_exception()
        raise


@bind_context(uri_pre + '/save')
def doctor_save(ctx, doctor_id, data_info):
    """
    保存医生数据
    create by oldman at 2017-02-23
    :param ctx:
    :param doctor_id: 医生ID
    :param data_info: 医生信息
    :return:
    """
    try:

        user = ctx.session.user
        if doctor_id is None:
            raise ValueError('doctor_id is None')
        doctor = Doctor.objects.get(id=doctor_id)
        old_name = doctor.name
        with transaction.atomic():
            if doctor.doctor_type == DOCTOR_TYPE.OFFICER:
                hospital = Hospital.objects.get(id=data_info['hospital_id'])
                office_count = Doctor.objects.filter(hospital=hospital, doctor_type=DOCTOR_TYPE.OFFICER). \
                    exclude(id=doctor_id).count()
                if office_count > 0:
                    raise gen(CODES.HOSPITAL_HAD_OFFICER)

                # 7680 添加医院规模
                hospital_scale = data_info.pop('hospital_scale')
                if hospital_scale is not None and isinstance(hospital_scale, basestring) and \
                        hospital_scale.isdigit() and HOSPITAL_SCALE.getDesc(int(hospital_scale)) is not None:
                    hospital_scale = int(hospital_scale)
                    try:
                        hospital.hospital_extra.scale = hospital_scale
                        hospital.hospital_extra.save()
                    except ObjectDoesNotExist:
                        Hospital_Extra(hospital=hospital, scale=hospital_scale).save()

            old_business = doctor.business_partener.id if doctor.business_partener else None
            new_business = data_info.get('business_partener_id', None)
            # 医生商务关联器
            if old_business != new_business:
                docrecord = DocBusinessRecord()
                docrecord.doctor_id = doctor.id
                docrecord.to_business_id = new_business
                docrecord.business_id = old_business
                docrecord.user = user
                docrecord.save()
            tags = data_info.pop('tags')
            specialtag = data_info.pop('specialtag', [])
            tags = tags + specialtag
            project_data = data_info.pop('project_data')
            if data_info['is_merchant'] and not doctor.is_merchant:
                data_info['become_merchant_time'] = datetime.datetime.now()
            for key, value in data_info.iteritems():
                setattr(doctor, key, value)
            doctor.save()
            sync_doctor_name_to_user(doctor, old_name, doctor.name)

            if tags:
                new_tags = set(Tag.objects.filter(id__in=tags))
                old_tags = set(doctor.tags.all())
                for tag_obj in (new_tags - old_tags):
                    DoctorTag.objects.get_or_create(doctor_id=doctor.id, tag=tag_obj)
                DoctorTag.objects.filter(
                    doctor_id=doctor.id, tag__in=(old_tags - new_tags),
                ).delete()

            if project_data:

                old_projects = set(DocprojectTag.objects.filter(doctor_id=doctor_id))
                new_projects = set([DocprojectTag.objects.get_or_create(
                    doctor_id=doctor_id,
                    tag_id=item
                )[0] for item in project_data])
                for item in (old_projects - new_projects):
                    item.delete()

    except Exception:
        logging_exception()
        raise


@bind_context(uri_pre + '/get_review_detail')
def get_review_data(ctx, doctor_id):
    """
    获取医生的修改数据信息
    :param ctx:
    :param doctor_id: 医生id
    :return:
    """
    try:
        doctor = Doctor.objects.get(id=doctor_id)
        if doctor.status != DOCTOR_INFO_STATUS.APPLY_EDIT:
            raise gen(CODES.DOCTOR_STATUS_ERRO)
        else:
            review_record = DoctorEditRecord.objects.filter(doctor_id=doctor_id,
                                                            status=DOCTOR_INFO_STATUS.APPLY_EDIT). \
                order_by('-created_at').first()
            data = json.loads(review_record.content)
            # 初始化历史数据
            data['notice'] = data.get('notice', '')
            data['bed_count'] = data.get('bed_count', None)
            data['department_count'] = data.get('department_count', None)
            data['honor_introduction'] = data.get('honor_introduction', '')
            data['honor_pics'] = data.get('honor_pics', [])
            data['escort'] = data.get('escort', False)
            data['one_to_one_consulation'] = data.get('one_to_one_consulation', False)
            data['regular_return_visit'] = data.get('regular_return_visit', False)
            data['wifi'] = data.get('wifi', False)
            data['paid_parking'] = data.get('paid_parking', False)
            data['independent_treatment_room'] = data.get('independent_treatment_room', False)
            data['dressing_room'] = data.get('dressing_room', False)
            data['free_parking_space'] = data.get('free_parking_space', False)
            data['smoking_room'] = data.get('smoking_room', False)
            data['free_drink'] = data.get('free_drink', False)
            data['free_snack'] = data.get('free_snack', False)
            data['swip'] = data.get('swip', False)

            title = data.get('title', '0')
            try:
                data['title'] = DOCTOR_TITLE_TYPE.getDesc(title)
            except:
                data['title'] = DOCTOR_TITLE_TYPE.getDesc(DOCTOR_TITLE_TYPE.EMPTY)

            data['title_type'] = title if title in [item[0] for item in DOCTOR_TITLE_TYPE.choices] else \
                DOCTOR_TITLE_TYPE.EMPTY
            if data['id'] != doctor.id:
                raise ValueError('医生ID和审核记录ID不一致！')

            recommend_services = data.get('recommend_services', [])
            data['recommend_services'] = ','.join([x['name'] for x in recommend_services])
            if doctor.doctor_type == DOCTOR_TYPE.DOCTOR:
                data['area_type'] = doctor.area_type
                data['doctor_type'] = doctor.doctor_type
                if data.get('professional_certificate_time_float', None):
                    data['professional_certificate_time'] = get_datetime(float(
                        data.get('professional_certificate_time_float'))).strftime("%Y-%m-%d")
                else:
                    data['professional_certificate_time'] = ''
                data['hospital_desc'] = doctor.hospital.name if doctor.hospital else ''

            else:
                recommend_doctors = data.get('recommend_doctors', [])
                data['recommend_doctors'] = ','.join([x['name'] for x in recommend_doctors])
                data['video_url'] = settings.VIDEO_HOST + data.get('video_url', '')
                data['hospital_desc'] = doctor.hospital.name if doctor.hospital else ''
                if data.get('open_time', None):
                    data['open_time'] = data['open_time'][0:7]
                else:
                    data['open_time'] = ''
            return data
    except Exception:
        logging_exception()
        raise


@bind_context(uri_pre + '/doctor_review/result')
def doctor_review_result(ctx, doctor_id, reason, is_pass):
    """
    审核医生申请修改资料
    create by oldman at 2017-02-28
    :param reason:拒绝原因
    :param is_pass:审核是否通过
    :param ctx:
    :param doctor_id: 医生ID
    :return:
    """
    try:
        video_id = None  # 用于异步处理水印
        with transaction.atomic():
            person = ctx.session.user.person
            doctor = Doctor.objects.get(id=doctor_id)
            if doctor.status != DOCTOR_INFO_STATUS.APPLY_EDIT:
                raise gen(CODES.DOCTOR_STATUS_ERRO)
            review_record = DoctorEditRecord.objects.filter(doctor_id=doctor_id,
                                                            status=DOCTOR_INFO_STATUS.APPLY_EDIT). \
                order_by('-created_at').first()
            data = json.loads(review_record.content)
            if is_pass:
                old_phone = doctor.phone
                doctor.status = DOCTOR_INFO_STATUS.CHECKED
                doctor.name = data.get('name', '')
                doctor.title = data.get('title', '')
                doctor.introduction = data.get('introduction', '')
                doctor.good_at = data.get('good_at', '')
                doctor.phone = data.get('phone', '')
                doctor.assist_phone = data.get('assist_phone', '')
                doctor.department = data.get('department', '')
                doctor.portrait = data.get('portrait', '')
                doctor.save()
                # 医生的额外信息
                if doctor.doctor_type == DOCTOR_TYPE.DOCTOR:
                    doctor_extra = Doctor_Extra.objects.get_or_create(doctor_id=doctor.id)[0]
                    doctor_extra.professional_certificate_num = data.get('professional_certificate_num', '')

                    if data.get('professional_certificate_time_float', None):
                        doctor_extra.professional_certificate_time = get_datetime(
                            float(data.get('professional_certificate_time_float', ))).date()
                    doctor_extra.save()
                    personalized_photo_album = data.get('personalized_photo_album', [])
                    # 更新医生的照片
                    data_image = {DOCTOR_LICENCE_TYPE.DOCTOR_PERSONALIZED_PHOTO_ALBUM: personalized_photo_album}
                    doctor.update_image_doctor(data_image)
                    # 更新医生的美购推荐
                    if data.get('recommend_services', None):
                        services = data.get('recommend_services', [])
                        doctor.update_recommend_service([service['id'] for service in services])
                # 医院的额外信息
                if doctor.doctor_type == DOCTOR_TYPE.OFFICER:

                    hospital = doctor.hospital
                    hospital.description = doctor.introduction
                    hospital.save()
                    # 更新医院的美购推荐
                    if data.get('recommend_services', None):
                        services = data.get('recommend_services', [])
                        hospital.update_recommend_services([service['id'] for service in services])
                    # 更新医院的医生推荐
                    if data.get('recommend_doctors', None):
                        doctors = data.get('recommend_doctors', [])
                        hospital.update_recommend_doctors([x['id'] for x in doctors])
                    instrument, _ = HospitalInstrument.objects.get_or_create(hospital=hospital)
                    instrument.intro = data.get('instrument_intro', '')
                    instrument.content = json.dumps(data.get('instrument_info') or [])
                    instrument.save()

                    video, _ = HospitalVideo.objects.get_or_create(hospital=hospital)
                    video.video_pic = data.get('video_pic', '')
                    video.video_url = data.get('video_url', '')
                    video.water_url = ''
                    video.persistentId = ''
                    video.persistent_status = VIDEO_CODE_STATUS.NOSTART
                    video.save()
                    if video.video_url:
                        # 事务外异步任务
                        video_id = video.id

                    hospital_extras = Hospital_Extra.objects.filter(
                        hospital_id=doctor.hospital.id
                    )
                    if hospital_extras.exists():
                        hospital_extra = hospital_extras.first()
                    else:
                        hospital_extra = Hospital_Extra(hospital_id=doctor.hospital.id)
                    keys = ['open_time', 'hospital_type', 'hospital_level', 'business_area',
                            'is_same_province_chain', 'is_inter_province_chain', 'notice', 'bed_count',
                            'department_count', 'honor_introduction'
                            ]
                    for key in keys:
                        setattr(hospital_extra, key, data.get(key, None))
                    if hospital_extra.hospital_level == None or hospital_extra.hospital_level == '':
                        hospital_extra.hospital_level = HOSPITAL_LEVEL.NONE
                    if hospital_extra.hospital_type == None or hospital_extra.hospital_type == '':
                        hospital_extra.hospital_type = HOSPITAL_MEDICAL_TYPE.NONE
                    if not hospital_extra.business_area:
                        hospital_extra.business_area = 0
                    if not hospital_extra.is_same_province_chain:
                        hospital_extra.is_same_province_chain = False
                    if not hospital_extra.is_inter_province_chain:
                        hospital_extra.is_inter_province_chain = False

                    if not data.get('open_time', None):
                        hospital_extra.open_time = datetime.date.min
                    if hospital_extra.business_area:
                        hospital_extra.business_area = int(hospital_extra.business_area)

                    hospital_extra.same_province_chain_hospital_id = data.get('same_province_chain_hospital', None)
                    hospital_extra.inter_province_chain_hospital_id = data.get('inter_province_chain_hospital', None)
                    if data.get('ad_check_img', None):
                        hospital_extra.ad_check_img = data.get('ad_check_img', None)
                    if data.get('ad_check_start_time', None):
                        hospital_extra.ad_check_start_time = datetime.datetime.strptime(
                            data.get('ad_check_start_time'), '%Y-%m-%d'
                        )
                    if data.get('ad_check_end_time', None):
                        hospital_extra.ad_check_end_time = datetime.datetime.strptime(
                            data.get('ad_check_end_time'), '%Y-%m-%d'
                        )
                    if data.get('practice_start_time', None):
                        hospital_extra.practice_start_time = datetime.datetime.strptime(
                            data.get('practice_start_time'), '%Y-%m-%d'
                        )
                    if data.get('practice_end_time', None):
                        hospital_extra.practice_end_time = datetime.datetime.strptime(
                            data.get('practice_end_time'), '%Y-%m-%d'
                        )
                    if hospital_extra.bed_count:
                        hospital_extra.bed_count = int(hospital_extra.bed_count)

                    if hospital_extra.department_count:
                        hospital_extra.department_count = int(hospital_extra.department_count)

                    if hospital_extra.honor_introduction is None:
                        hospital_extra.honor_introduction = ''
                    hospital_extra.save()

                    hospital_rest_assure = HospitalRestAssured.objects.filter(
                        hospital_id=doctor.hospital.id
                    )
                    if hospital_rest_assure.exists():
                        hospital_rest_assure = hospital_rest_assure.first()
                    else:
                        hospital_rest_assure = HospitalRestAssured(hospital_id=doctor.hospital.id)
                    hospital_rest_assure.escort = data.get('escort', False)
                    hospital_rest_assure.one_to_one_consulation = data.get('one_to_one_consulation', False)
                    hospital_rest_assure.regular_return_visit = data.get('regular_return_visit', False)
                    hospital_rest_assure.save()

                    hospital_special_service = HospitalSpecialService.objects.filter(
                        hospital_id=doctor.hospital.id
                    )
                    if hospital_special_service.exists():
                        hospital_special_service = hospital_special_service.first()
                    else:
                        hospital_special_service = HospitalSpecialService(hospital_id=doctor.hospital.id)
                    hospital_special_service.dressing_room = data.get('dressing_room', False)
                    hospital_special_service.free_drink = data.get('free_drink', False)
                    hospital_special_service.free_parking_space = data.get('free_parking_space', False)
                    hospital_special_service.free_snack = data.get('free_snack', False)
                    hospital_special_service.independent_treatment_room = data.get('independent_treatment_room', False)
                    hospital_special_service.paid_parking = data.get('paid_parking', False)
                    hospital_special_service.smoking_room = data.get('smoking_room', False)
                    hospital_special_service.swip = data.get('swip', False)
                    hospital_special_service.wifi = data.get('wifi', False)
                    hospital_special_service.save()

                    if doctor.is_merchant:
                        from hippo.models.merchant import MerchantLicense
                        mls = MerchantLicense.objects.filter(merchant_id=doctor.merchant.id)
                        if mls.exists():
                            ml = mls.first()
                            ml.lincense_img = data.get('b_licences')[0] if data.get('b_licences', None) else ''
                            ml.lincense_name = data.get('lincense_name', '')
                            ml.lincense_number = data.get('lincense_number', '')
                            ml.lincense_start_time = datetime.datetime.strptime(
                                data.get('lincense_start_time'), '%Y-%m-%d'
                            )
                            if data.get('lincense_end_time', None):
                                ml.lincense_end_time = datetime.datetime.strptime(
                                    data.get('lincense_end_time'), '%Y-%m-%d'
                                )
                            ml.save()
                        else:
                            ml = MerchantLicense(merchant_id=doctor.merchant.id)
                            ml.lincense_img = data.get('b_licences')[0] if data.get('b_licences', None) else ''
                            ml.lincense_name = data.get('lincense_name', '')
                            ml.lincense_number = data.get('lincense_number', '')
                            ml.lincense_start_time = datetime.datetime.strptime(
                                data.get('lincense_start_time'), '%Y-%m-%d'
                            )
                            if data.get('lincense_end_time', None):
                                ml.lincense_end_time = datetime.datetime.strptime(
                                    data.get('lincense_end_time'), '%Y-%m-%d'
                                )
                            ml.save()
                    data_image = {
                        DOCTOR_LICENCE_TYPE.HOSPITAL_LEVEL: data.get('level_image', []),
                        DOCTOR_LICENCE_TYPE.RETAIL_LEASE_CONTRACT: data.get('area_image', []),
                        DOCTOR_LICENCE_TYPE.SAME_PROVINCE_CHAIN_HOSPITAL: data.get('same_p_image', []),
                        DOCTOR_LICENCE_TYPE.INTER_PROVINCE_CHAIN_HOSPITAL: data.get('inter_p_image', []),
                        DOCTOR_LICENCE_TYPE.HOSPITAL_HONOR_PICTURE: data.get('honor_pics', []),

                    }
                    doctor.update_image_doctor(data_image)

                if old_phone != doctor.phone:
                    doctor.register_phone_ext()
                doctor.update_licence_images(data.get('b_licences', []),
                                             data.get('p_licences', []),
                                             data.get('t_licences', []))
                if doctor.user:
                    if doctor.doctor_type == DOCTOR_TYPE.DOCTOR:
                        doctor.user.last_name = u'{} 医生'.format(data.get('name', ''))
                    else:
                        doctor.user.last_name = data.get('name', '')
                    doctor.user.save()
                    doctor.user.userextra.portrait = data.get('portrait', '')
                    doctor.user.userextra.save()
                # account_info = data.get('doctor_account', None)
                # if account_info:
                #     doctor_account = DoctorAccount.objects.get_or_create(doctor_id=doctor.id)[0]
                #     doctor_account.account_type = account_info.get('account_type', '')
                #     doctor_account.account_name = account_info.get('account_name', '')
                #     doctor_account.bank = account_info.get('bank', '')
                #     doctor_account.account_number = account_info.get('account_number', '')
                #     doctor_account.save()

                if doctor.doctor_type == DOCTOR_TYPE.OFFICER:
                    doctor.update_hospital_pics(data.get('hospital_pics', []))
                review_record.status = DOCTOR_INFO_STATUS.CHECKED
                review_record.handler = person
                review_record.save()
            else:
                doctor.status = DOCTOR_INFO_STATUS.REJECT
                doctor.save()
                review_record.status = DOCTOR_INFO_STATUS.REJECT
                review_record.reject_reason = reason
                review_record.handler = person
                review_record.save()
        if video_id is not None:
            set_water_mark_to_video_hospital.delay(video_id)
    except Exception as e:
        logging_exception()
        raise


@bind_context(uri_pre + '/get_account_detail')
def get_account_data(ctx, doctor_id):
    """
    获取医生的结算信息
    :param ctx:
    :param doctor_id: 医生id
    :return:
    """
    try:
        doctor = Doctor.objects.get(id=doctor_id)
        if doctor.merchant.account.status != DOCTOR_ACCOUNT_STATUS.SUBMITED:
            raise gen(CODES.DOCTOR_STATUS_ERRO)
        else:
            account_record = MerchantAccountRecord.objects.filter(account__merchant__doctor_id=doctor_id).last()

            data = json.loads(account_record.content)
            data['name'] = doctor.name
            data['title'] = doctor.title
            data['area_type'] = doctor.area_type

            data['address'] = doctor.hospital.city.name if doctor.hospital and doctor.hospital.city else ''
            data['doctor_type'] = doctor.doctor_type
            data['hospital'] = doctor.hospital.name
            data['login_phone'] = doctor.user.person.phone
            data['phone'] = doctor.phone
            data['business_partener'] = doctor.business_partener.last_name
            content = data.get('content')
            if content.get('city_id', None):
                try:
                    data['city_name'] = FinanceCity.objects.get(id=content.get('city_id', None)).name
                except:
                    data['city_name'] = ''
            else:
                data['city_name'] = ''
            if data['doctor_id'] != doctor.id:
                raise ValueError('医生ID和审核记录ID不一致！')
            return data
    except Exception:
        logging_exception()
        raise


@bind_context(uri_pre + '/doctor_account/result')
def doctor_review_result(ctx, doctor_id, reason, is_pass):
    """
    审核医生申请结算信息资料
    create by esse at 2017-05-03
    :param reason:拒绝原因
    :param is_pass:审核是否通过
    :param ctx:
    :param doctor_id: 医生ID
    :return:
    """
    try:
        with transaction.atomic():
            person = ctx.session.user.person
            doctor = Doctor.objects.get(id=doctor_id)
            if doctor.merchant.account.status != DOCTOR_ACCOUNT_STATUS.SUBMITED:
                raise gen(CODES.DOCTOR_STATUS_ERRO)
            account_record = MerchantAccountRecord.objects.filter(account__merchant__doctor_id=doctor_id).last()
            account = MerchantAccount.objects.get(merchant__doctor_id=doctor_id)
            data = json.loads(account_record.content)
            if is_pass:
                account.update_time = datetime.datetime.today()
                account.status = DOCTOR_ACCOUNT_STATUS.CHECKED
                account.bank = data['content']['bank']
                account.account_type = data['content']['account_type']
                account.account_name = data['content']['account_name']
                account.account_number = data['content']['account_number']
                account.subbranch = data['content'].get('z_bank', '')
                account.city_finance_id = data['content'].get('city_id', None)
                new_record = MerchantAccountRecord()
                new_record.account_id = account.id
                new_record.status = DOCTOR_ACCOUNT_STATUS.CHECKED
                new_record.handler = person
                new_record.content = account_record.content
                account.save()
                new_record.save()
            else:
                account.status = DOCTOR_ACCOUNT_STATUS.REJECT
                new_record = MerchantAccountRecord()
                new_record.account_id = account.id
                new_record.status = DOCTOR_ACCOUNT_STATUS.REJECT
                new_record.handler = person
                new_record.reject_reason = reason
                new_record.content = account_record.content
                account.save()
                new_record.save()
    except Exception as e:
        logging_exception()
        raise


@bind_context(uri_pre + '/set_online')
def doctor_set_online(ctx, doctor_id, is_online):
    """
    设置医生上下线
    create by oldman 2017-03-13
    :param ctx:
    :param doctor_id: 医生ID
    :param is_online: 上下线
    :return:
    """
    try:
        doctor = Doctor.objects.get(id=doctor_id)
        if is_online:
            if doctor.hospital is None:
                return {
                    'code': 2,
                    'message': u'医生关联医院不能为空！'
                }
            if doctor.business_partener is None:
                return {
                    'code': 3,
                    'message': u'医生关联商务不能为空！'
                }
        else:
            delete_service_rank.delay(doctor_id=doctor_id)
        doctor.is_online = is_online
        doctor.save()
        return {
            'code': 1,
            'message': u'保存成功！',
        }
    except Exception:
        pass


@bind_context(uri_pre + '/get_hospital')
def doctor_get_hospital(ctx, doctor_ids):
    result = []
    for doctor_id in doctor_ids:
        doctor_data = {}
        doctor = Doctor.objects.get(id=doctor_id)
        doctor_data['id'] = doctor.id
        doctor_data['name'] = doctor.name
        doctor_data['title'] = doctor.title
        doctor_data['hospital_name'] = getattr(doctor.hospital, 'name', '')
        result.append(doctor_data)
    return result


@bind_context(uri_pre + '/getidsbyname')
def get_doctoridsbyname(ctx, name):
    """
    根据医生姓名获取医生ID
    :param ctx:
    :param name:医生姓名
    :return:
    """
    try:
        doctors = Doctor.objects.using(settings.SLAVE_DB_NAME).filter(name__contains=name)
        if doctors:
            return ','.join([doctor.id for doctor in doctors])
        else:
            return None
    except Exception:
        logging_exception()
        return None


@bind_context(uri_pre + '/getidsbyhospitalname')
def get_doctoridsbyhospitalname(ctx, name):
    """
    根据医院姓名姓名获取医生ID
    :param ctx:
    :param name:医院姓名
    :return:
    """
    try:
        hospital = Hospital.objects.using(settings.SLAVE_DB_NAME).filter(name__contains=name)
        hospital_ids = [item.id for item in hospital]
        doctors = Doctor.objects.filter(hospital_id__in=hospital_ids)
        if doctors:
            return ','.join([doctor.id for doctor in doctors])
        else:
            return None
    except Exception:
        logging_exception()
        return None


@bind_context(uri_pre + '/getidsbybusinessname')
def get_doctoridsbyhospitalname(ctx, name):
    """
    根据商务姓名姓名获取医生ID
    :param ctx:
    :param name:商务姓名
    :return:
    """
    try:
        users = User.objects.using(settings.SLAVE_DB_NAME).filter(last_name__contains=name)
        user_ids = [item.id for item in users]
        doctors = Doctor.objects.filter(business_partener_id__in=user_ids)
        if doctors:
            return ','.join([doctor.id for doctor in doctors])
        else:
            return None
    except Exception:
        logging_exception()
        return None


@bind_context(uri_pre + '/getdoctorinfo_by_id')
def get_doctorinfobyid(ctx, doctor_id):
    """
    根据医生ID获取医生部分信息(姓名，医院，城市，商务)
    :param ctx:
    :param doctor_id:
    :return:
    """

    try:
        doctor = Doctor.objects.get(id=doctor_id)
        business_name = ''
        if doctor.business_partener:
            if doctor.business_partener.last_name:
                business_name = doctor.business_partener.last_name
            else:
                business_name = doctor.business_partener.username
        team = ''
        if doctor.business_group:
            team = Team.objects.get(id=doctor.business_group).name
        try:
            merchant = MerchantRelevance.objects.get(doctor_id=doctor.id, merchant__is_online=True).merchant
        except:
            merchant = None
        return {
            'doctor_id': doctor.id,
            'doctor_name': doctor.name,
            'hospital_name': doctor.hospital.name if doctor.hospital else '',
            'hospital_id': doctor.hospital.id if doctor.hospital else '',
            'business_name': business_name,
            'city': doctor.hospital.city.name if
            (doctor.hospital if doctor.hospital and doctor.hospital.city else None) else '',
            'city_id': doctor.hospital.city.id if
            (doctor.hospital if doctor.hospital and doctor.hospital.city else None) else '',
            'province_id': doctor.hospital.city.province_id if
            (doctor.hospital if doctor.hospital and doctor.hospital.city else None) else '',
            'phone': doctor.phone if doctor.phone else '',
            'team': team,
            'login_phone': doctor.user.person.phone if doctor.user and doctor.user.person.phone else '',
            'business_id': doctor.business_partener_id if doctor.business_partener_id else '',
            'business_group': doctor.business_group,
            'merchant_id': merchant.id if merchant else ''
        }
    except Exception as e:
        logging_exception()
        return None


@bind_context(uri_pre + '/getdoctorinfo_byids')
def get_doctorinfo_byids(ctx, doctor_ids):
    """
    根据医生ids获取医生信息(姓名，医院，城市，商务)
    :param ctx:
    :param doctor_ids:
    :return:
    """
    doctors = Doctor.objects.filter(id__in=doctor_ids)
    result = []

    for doctor in doctors:
        try:
            result.append({
                'doctor_id': doctor.id,
                'doctor_name': doctor.name,
                'hospital_name': doctor.hospital.name if doctor.hospital else '',
                'business_name': doctor.business_partener.last_name if doctor.business_partener else '',
                'city': doctor.hospital.city.name if (doctor.hospital if doctor.hospital else None) else ''
            })
        except Exception:
            logging_exception()
            continue
    return result


@bind_context(uri_pre + '/get_doctors')
def get_doctors(ctx):
    """
    根据请求用户获取商务的管理的医生
    :param ctx:
    :return:
    """
    is_not_business_leader = check_business(ctx.session.groups)
    doctors = []
    if is_not_business_leader:
        # 判断是商务并且非商务leader
        user = ctx.session.user
        members = UserPerm.members(user)
        doctors_res = Doctor.objects.filter(business_partener__in=members).values_list('id', flat=True)
        doctors.extend(doctors_res)
    return {
        'is_not_business_leader': is_not_business_leader,
        'doctors': ','.join(doctors)
    }


@bind_context(uri_pre + '/getidsbylogin_phone')
def get_doctoridsbyhospitalname(ctx, phone):
    """
    根据医生登录手机号获取医生ID
    :param ctx:
    :param phone:医生登录手机号
    :return:
    """
    try:
        doctors = Doctor.objects.filter(user__person__phone=phone)
        if doctors:
            return ','.join([doctor.id for doctor in doctors])
        else:
            return None
    except Exception:
        logging_exception()
        return None


@bind_context(uri_pre + '/getidsbyphone')
def get_doctoridsbyhospitalname(ctx, phone):
    """
    根据医生联系手机号获取医生ID
    :param ctx:
    :param phone:医生登录手机号
    :return:
    """
    try:
        doctors = Doctor.objects.filter(phone=phone)
        if doctors:
            return ','.join([doctor.id for doctor in doctors])
        else:
            return None
    except Exception:
        logging_exception()
        return None


@bind_context(uri_pre + '/pos/update')
def pos_update_code(ctx, doctor_id, code):
    defaults = {'code': code}
    POSMachine.objects.update_or_create(doctor_id=doctor_id, defaults=defaults)
    pass


@bind_context(uri_pre + '/posrecord/insert')
def pos_update(ctx, pos_list):
    _pay_code = lambda x: 'kuaiqian' + str(int(float(x[0])))
    pos_list = filter(lambda x: x[3].strip() == u'交易成功', pos_list)
    machine_code = set([x[4] for x in pos_list])
    doctors = {x.code: x.doctor for x in POSMachine.objects.filter(code__in=machine_code)}
    if len(doctors) != len(machine_code):
        raise gen(CODES.UNBIND_MACHINE_CODE)
    inserted = [x.pay_code for x in POSRecord.objects.filter(pay_code__in=[_pay_code(y) for y in pos_list])]
    for x in filter(lambda x: _pay_code(x) not in inserted, pos_list):
        doctor = doctors[x[4]]
        POSRecord.objects.create(
            pay_code=_pay_code(x), amount=x[1],
            record_time=x[2], doctor=doctor
        )
        pos, _ = POSSum.objects.get_or_create(doctor=doctor, day=x[2][:10])
        pos.amount += x[1]
        pos.save()


@bind_context(uri_pre + '/get_doctor_ids_by_business_group')
def get_doctor_ids_by_business_group(ctx, business_group):
    """
    根据商务分组获取医生IDs
    :param ctx:
    :param business_group:
    :return:
    """
    doctors = Doctor.objects.filter(business_group=business_group)
    return [doctor.id for doctor in doctors]


@bind_context(uri_pre + 'get_doctor_phone_from_record')
def get_doctor_phone_from_record(ctx, id_):
    """
    根据记录id获取医生手机号
    :param ctx:
    :param id_:
    :return: phone:
    """
    record = PhoneServiceRecord.objects.get(id=id_)
    return record.call_phone
