#!/usr/bin/env python
# coding=utf-8

from __future__ import unicode_literals, absolute_import

import datetime
import json
import math
import random

from django.conf import settings
from django.contrib.auth.models import User
from django.db import models
from django.db.models import Q, F
from django.utils import timezone
from gm_types.ascle.types import HOSPITAL_INFO_IMAGE, HOSPITAL_INFO_REVIEW
from gm_types.doctor import DOCTOR_AREA_TYPE, DOCTOR_LICENCE_TYPE, DOCTOR_INFO_STATUS, DOCTOR_ACCOUNT_TYPE, \
    DOCTOR_ACCOUNT_STATUS, DOCTOR_TITLE_TYPE
from gm_types.gaia import (
    DOCTOR_PROCESS_STATUS, DOCTOR_TYPE, PHONE_HINTS, TOPIC_TYPE, TAG_TYPE, DisplayTag,
    SERVICE_FLAG)
from gm_upload import ImgUrlField, IMG_TYPE

from api.models.area import Province, City, Country
from api.models.bodypart import BodyPart
from api.models.bodypartsubitem import BodyPartSubItem
from api.models.person import Person
from api.models.tag import Tag
from api.tool.datetime_tool import get_monday, get_timestamp_epoch, get_timestamp
from api.tool.image_utils import get_full_path
from hippo.models.finance import FinanceCity
from lasker.models import AwardResult
from rpc.cache import (
    doctor_tags_cache,
    doctor_tagv3s_cache,
    hospital_doctor_service_cache,
    doctor_search_tags_cache,
    hospital_search_tags_cache,
    share_diary_num_cache,
    doctor_sell_amount_cache,
    doctor_service_tags_distribution_cache,
    doctor_badge_cache,
)
from rpc.tool.dict_mixin import to_dict
from rpc.tool.error_code import gen, CODES
from rpc.tool.log_tool import exception_logger, logging_exception
from rpc.tool.random_tool import random_str
from search.utils.diary import filter_diary
from services.custom_phone_service import Phone400Service
from services.custom_phone_service import PhoneService
from themis.models import Team
from utils.uuid4 import uuid4
from .hospital import Hospital


class DoctorCategory(models.Model):
    class Meta:
        verbose_name = u'32. 医生_分类'
        verbose_name_plural = u'32. 医生_分类'
        db_table = 'api_doctorcategory'
        app_label = 'api'

    name = models.CharField(max_length=30, unique=True, verbose_name=u"医生类别")
    rank = models.IntegerField(default=0, verbose_name=u"排序", help_text=u"越小越排在前面")
    is_deleted = models.BooleanField(default=False, verbose_name=u"删除")

    def __unicode__(self):
        return self.name


class Doctor(models.Model):
    """
        假定医生和医院不会太多
    """

    class Meta:
        verbose_name = u'31. 医生'
        verbose_name_plural = u'31. 医生'
        db_table = 'api_doctor'
        app_label = 'api'

    id = models.CharField(max_length=100, primary_key=True, default=uuid4)
    user = models.OneToOneField(User, default=None, null=True, blank=True)
    name = models.CharField(max_length=200, verbose_name=u"姓名", db_index=True)
    portrait = ImgUrlField(img_type=IMG_TYPE.DOCTOR, max_length=200, help_text=u"医生头像", blank=True, default='')

    title = models.CharField(max_length=200, verbose_name=u"职称", choices=DOCTOR_TITLE_TYPE,
                             default=DOCTOR_TITLE_TYPE.EMPTY)
    hospital = models.ForeignKey(Hospital, null=True, blank=False, related_name="doctor_hospital", verbose_name=u"医院")
    department = models.CharField(max_length=50, default="", help_text=u'医院科室')
    good_at = models.TextField(blank=True, verbose_name=u"擅长项目")
    introduction = models.TextField(blank=True, help_text=u"简介")
    phone = models.CharField(max_length=100, help_text=u"联系电话")
    # 现注册需求流程严格要求此不能更改, 2017-02-14
    doctor_type = models.CharField(max_length=1, default=DOCTOR_TYPE.DOCTOR,
                                   choices=DOCTOR_TYPE, null=False,
                                   verbose_name=u'医生类型')
    area_type = models.IntegerField(
        verbose_name=u'地域类型', choices=DOCTOR_AREA_TYPE, default=DOCTOR_AREA_TYPE.CISBORDER,
        null=True, blank=True
    )
    assist_phone = models.CharField(max_length=20, verbose_name=u"助理手机号码", null=True, blank=True)

    created_at = models.DateTimeField(verbose_name=u'创建时间', auto_now_add=True, null=True)
    last_answered_time = models.DateTimeField(default=datetime.datetime.fromtimestamp(0), verbose_name=u"最后一次答题时间")

    status = models.IntegerField(verbose_name=u'信息修改状态', choices=DOCTOR_INFO_STATUS, default=DOCTOR_INFO_STATUS.CHECKED)
    last_edit_time = models.DateTimeField(auto_now=True, verbose_name=u"最后一次提交修改的时间")
    # !!!! 运营 管理部分======================
    rate = models.FloatField(default=5.0, help_text=u"用户综合评分")
    rate_count = models.FloatField(help_text=u"用户综合评分(来自点评数据)", default=5.0)

    phone_ext = models.CharField(max_length=20, help_text=u"分机", null=True, blank=True, default="")
    phone_hint = models.CharField(max_length=1, default=PHONE_HINTS.PERSONAL_PHONE, choices=PHONE_HINTS,
                                  verbose_name=u"电话提示本文")

    is_online = models.BooleanField(default=False, help_text=u"是否上线", verbose_name=u"上线", db_index=True)
    online_time = models.DateTimeField(default=datetime.datetime.fromtimestamp(0), verbose_name=u"上线时间")

    is_recommend = models.BooleanField(help_text=u"是否推荐医生", verbose_name=u"推荐", default=False)
    accept_private_msg = models.BooleanField(default=False, verbose_name=u"是否接受私信")
    reply_limit = models.IntegerField(verbose_name=u'每日回复限制', default=3)

    business_partener = models.ForeignKey(User, default=None, null=True,
                                          verbose_name=u'负责此医生的商务同事',
                                          related_name='business_partener')
    business_group = models.IntegerField('组织架构的组织', null=True)
    related_doctor = models.ManyToManyField('self', verbose_name=u'关联医生')
    tip = models.CharField(max_length=128, null=False, verbose_name=u'标签', default='')
    allow_hospital_agent = models.BooleanField(default=False, verbose_name=u'是否允许医院托管代理')
    show_location = models.BooleanField(help_text=u"是否显示地理位置", verbose_name=u"是否显示地理位置", default=True)
    self_run = models.BooleanField(verbose_name=u'自营', default=False)
    big = models.BooleanField(verbose_name=u'大牌', default=False)

    effect_rating = models.FloatField(default=5.0, help_text=u"用户综合评分")  # 效果评分
    attitude_rating = models.FloatField(default=5.0, help_text=u"用户综合评分")  # 态度评分
    env_rating = models.FloatField(default=5.0, help_text=u"用户综合评分")  # 环境评分
    start_time = models.TimeField(default=datetime.time(hour=9), verbose_name=u"医生开始工作时间")
    end_time = models.TimeField(default=datetime.time(hour=19), verbose_name=u"医生结束工作时间")

    body_parts = models.ManyToManyField(BodyPart, verbose_name=u"身体部位", default=[1], blank=True)
    body_sub_items = models.ManyToManyField(BodyPartSubItem, related_name="doctor_subitem", default=[1])
    categories = models.ManyToManyField(DoctorCategory, related_name="doctor_categories", default=[11])
    tags = models.ManyToManyField(Tag, related_name="doctors", through="DoctorTag")
    project_tags = models.ManyToManyField(Tag, through="DocprojectTag")

    msg_noti_sound = models.BooleanField(verbose_name=u'开启声音', default=True)
    # !!!!======================================

    # Google坐标
    google_loc_lng = models.FloatField(default=0, help_text=u"经度(-180~180)")
    google_loc_lat = models.FloatField(default=0, help_text=u"纬度")

    # 每日统计信息
    view_num = models.IntegerField(verbose_name=u"专家详情浏览量", default=0)
    reply_num = models.IntegerField(verbose_name=u'回复', default=0)
    new_pm_num = models.IntegerField(verbose_name=u'新私信', default=0)
    reply_pm_num = models.IntegerField(verbose_name=u'回私信', default=0)
    no_reply_pm_num = models.IntegerField(verbose_name=u'未回私信', default=0)
    share_topic_num = models.IntegerField(verbose_name=u'案例', default=0)

    # <<<<<<<<废弃的 at 2017-02-14 整理
    # 医生端2.0.0的时候已经废弃，默认都打开，接收预约
    accept_reserve = models.BooleanField(default=True, verbose_name=u'是否接受预约')
    large_photo = ImgUrlField(img_type=IMG_TYPE.DOCTOR, max_length=200, verbose_name=u"医生顶部大图", null=True, blank=True,
                              default='')
    web_link = models.CharField(max_length=100, blank=True, null=True, default=None, verbose_name=u"网络链接")
    process_status = models.CharField(max_length=1, default=DOCTOR_PROCESS_STATUS.processed,
                                      choices=DOCTOR_PROCESS_STATUS, null=False, verbose_name=u"处理状态")
    operate_log = models.TextField(blank=True, null=True, default=None, verbose_name=u"操作记录")
    comments = models.CharField(max_length=50, null=True, blank=True, default='', verbose_name=u'备注')
    # 新浪微博部分
    access_token = models.CharField(max_length=32, null=True, blank=True, default=None)
    expires_in = models.IntegerField(null=True, default=0)

    business_licence = models.CharField(max_length=400, null=False, verbose_name=u'资格证', default='')
    practice_licence = models.CharField(max_length=400, null=False, verbose_name=u'执业证', default='')
    # BD需求
    doc_phone = models.CharField(max_length=20, verbose_name=u"医生个人电话", default='null')
    doc_address = models.CharField(max_length=100, verbose_name=u"医生个人地址", default='null')
    doc_email = models.CharField(max_length=100, verbose_name=u"医生个人邮箱", null=True, blank=True)
    doc_birthday = models.CharField(max_length=40, verbose_name=u"医生生日", null=True, blank=True)

    # >>>>>>>>>
    is_merchant = models.BooleanField(verbose_name=u'是否商户', default=False)
    become_merchant_time = models.DateTimeField(verbose_name=u'成为商户时间', null=True, blank=True)
    is_show = models.BooleanField(verbose_name=u'是否展示', default=True)

    @property
    def merchant(self):
        from hippo.models.merchant import MerchantRelevance
        try:
            merchant = MerchantRelevance.objects.get(doctor_id=self.id).merchant
        except MerchantRelevance.DoesNotExist:
            return None
        return merchant


    @property
    def is_store_classification(self):
        from hippo.models.chain_hospital import MasterMerchant
        """判断是否为旗舰店"""
        try:
            is_store_classification = MasterMerchant.objects.filter(
                mastermerchant_id=self.merchant.id, is_operetor_related=True, is_store_classification=True).exists()
        except:
            is_store_classification = False
        return is_store_classification


    @property
    def is_store_classification_child(self):
        from hippo.models.chain_hospital import SlaveMerchant
        """判断是否为旗舰店子店"""
        is_store_classification_child = False
        try:
            slave_merchant = SlaveMerchant.objects.filter(slavemerchant_id=self.merchant.id)
        except:
            return is_store_classification_child
        if slave_merchant:
            is_store_classification_child = slave_merchant.first().mastermerchant.is_store_classification
        return is_store_classification_child


    @property
    def is_recommend_doctor(self):
        # 现在这部分只有PC站在使用
        from talos.models.topic import Problem
        from hippo.models import DoctorItem
        doctoritem_ids = list(DoctorItem.objects.filter(doctor_id=self.id).values_list('id', flat=True))
        gte_date = datetime.date.today() - datetime.timedelta(days=30)
        share_filter = (
            Q(link_doctor_item_id__in=doctoritem_ids) & Q(created_time__gte=gte_date) & Q(topic_type=TOPIC_TYPE.SHARE)
        )
        is_recommend = Problem.objects.filter(share_filter).exists()
        return is_recommend

    @property
    def share_diary_num(self):
        """ 4.1.0 开始使用日记本统计案例数
        :return:
        """
        _id = self.id.encode("utf-8") if type(self.id) == unicode else self.id
        num = share_diary_num_cache.get(_id)
        if num:
            return int(num)

        num = 0
        try:
            # check hospital exist
            _ = self.hospital
        except Hospital.DoesNotExist:
            return num

        if self.doctor_type == DOCTOR_TYPE.OFFICER and self.hospital:
            num = self.hospital.share_diary_num

        elif self.doctor_type == DOCTOR_TYPE.DOCTOR:
            num = filter_diary(filters={'doctor_id': self.id}, expose_total=True)['total']

        share_diary_num_cache.setex(_id, 30 * 60, num)
        return num

    @property
    def is_hospital(self):
        return True if self.doctor_type == DOCTOR_TYPE.OFFICER else False

    @classmethod
    def generate_phone_ext(cls):
        while True:
            ext = '%s%s' % (random.randint(1, 9), random_str(5, digit=True))
            if len(set(ext)) == 1 or sorted(ext) == list(ext) or sorted(ext, reverse=True) == list(ext):
                # 保留特殊分机号
                # 数字完全相同
                # 顺序排列
                # 倒序排列
                continue
            if not cls.objects.filter(phone_ext=ext).exists():
                break
        return ext

    @classmethod
    def get_online_doctor_by_id(cls, doctor_id):
        return cls.objects.filter(id=doctor_id, is_online=True).first()

    @property
    def accept_call(self):
        return bool(self.phone and self.phone_ext)

    def badges(self):
        """获取医生医院的是否有名医大赏的标签"""
        try:
            award_name = doctor_badge_cache.get(self.id)
            if award_name is None:
                result = AwardResult.objects.filter(
                    laureate_id=self.id, is_deleted=False,
                    laureate_type=SERVICE_FLAG.DOCTOR if self.doctor_type == DOCTOR_TYPE.DOCTOR else SERVICE_FLAG.HOSPITAL
                ).first()
                if result and result.award_name:
                    award_name = json.dumps(result.award_name.split(','))
                else:
                    award_name = json.dumps([])
                doctor_badge_cache.set(self.id, award_name, ex=24 * 60 * 60)
            return json.loads(award_name)
        except:
            return []

    def get_award_name_and_is_special_skin(self):
        #  获取医生 名医大赏荣誉和是否有特殊皮肤
        award_name, is_special_skin = AwardResult.get_award_result_with_laureate_id(self.id, self.doctor_type)

        if not award_name and self.doctor_type == DOCTOR_TYPE.OFFICER:
            # 如果没用名医大赏荣誉名称 并且 是机构管理者， 则获取医院的名医大赏荣誉
            try:
                # check hospital exist
                _ = self.hospital
            except Hospital.DoesNotExist:
                return award_name, is_special_skin
            if self.hospital:
                award_name, is_special_skin = AwardResult.get_award_result_with_laureate_id(self.hospital.id)

        return award_name, is_special_skin

    @classmethod
    def get_doctor_tag_count_dict(cls, ctx, device_id, doctor_ids, query):
        # 医生或医院标签及案例接口
        case_list = ctx.rpc_remote['doris/search/tag_count'](
            device_id=device_id,
            doctor_list=doctor_ids,
            query=query
        ).unwrap()
        case_dict = dict()
        for item in case_list:
            for doctor_id in item:
                case_dict[doctor_id] = item[doctor_id]
        return case_dict

    @classmethod
    def get_cases_str(cls, case_dict, id):
        cases = case_dict.get(id, [])
        temp = []
        for case_item in cases:
            temp.append({"name": u'{} {}例'.format(case_item.get('tag'), case_item.get('count')), "tag_id": 0})
        return temp

    def cases(self,case_dict=None):
        if case_dict:
            return Doctor.get_cases_str(case_dict,self.id)
        if self.doctor_type == DOCTOR_TYPE.DOCTOR:
            _, doctor_items = self.get_doctor_item_list()
            return doctor_items
        else:
            hospital_items = {}
            hospital_doctors = self.hospital.doctor_hospital.all()
            for doctor in hospital_doctors:
                if doctor.is_online is False:
                    continue
                _, doctor_items = doctor.get_doctor_item_list()
                for item in doctor_items:
                    names = item['name'].replace('例', '').rsplit(" ", 1)
                    item_dict = {'name': names[0], "cnt": int(names[-1]), "tag_id": item['tag_id']}

                    if hospital_items.get(item_dict['name']):
                        hospital_items[item_dict['name']]['cnt'] += item_dict['cnt']
                    else:
                        hospital_items[item_dict['name']] = item_dict
            hospital_items = sorted(hospital_items.values(), key=lambda x: x['cnt'], reverse=True)
            item_list_raw = [{'name': u'{} {}例'.format(v['name'], v['cnt']), 'tag_id': v['tag_id']} for v in
                             hospital_items]
            return item_list_raw

    def format_display_tags(self, hospital_scale, badges, operate_tags):
        """处理显示的tag 将名医大赏和个性化标签合成一个tag, display_tags 为7680添加

        :param hospital_scale: 医院规模
        :param badges: 名医大赏标签
        :param operate_tags: 运营标签
        :rtype: dict
        """
        display_tags = []
        if self.doctor_type == DOCTOR_TYPE.OFFICER and hospital_scale:
            display_tags.append({"name": hospital_scale, "type": DisplayTag.HOSPITAL_SCALE})
        for badge_name in badges:
            display_tags.append({"name": badge_name, "type": DisplayTag.BADGE})
        for operate_tag in operate_tags:
            operate_tag.update({"type": DisplayTag.OPERATE_TAG})
            display_tags.append(operate_tag)
        return display_tags

    def register_phone_ext(self, force=False):
        """将医生手机和分机号注册到400服务商处
        """
        if not self.phone:
            return
        if len(self.phone_ext) == 4 and self.phone_ext != '6666':
            # 4位分机号是老的服务商，不处理
            return
        # if settings.DEBUG:
        #     return
        p4s = Phone400Service()
        try:
            if self.phone_ext and not force:
                # 分机号存在，更新手机号
                p4s.update(self.phone_ext, self.phone)
            else:
                self.phone_ext = self.generate_phone_ext()
                p4s.create(self.phone_ext, self.phone)
        except Exception as e:
            logging_exception()
            exception_logger.error('%s %s %s %s' % (self.id, self.phone, self.phone_ext, e.message))
            raise gen(CODES.DOCTOR_REG_PHONE_EXT_ERROR)

        self.save()

        # ##### old code, should be removed #####
        # ph_serv = PhoneService()
        # if self.phone_ext and not force:
        #     # 分机号存在，更新手机号
        #     ret = ph_serv.update(self.phone, self.phone_ext)
        # else:
        #     self.phone_ext = self.generate_phone_ext()
        #     ret = ph_serv.save(self.phone, self.phone_ext)
        # if ret['success']:
        #     self.save()
        # else:
        #     exception_logger.error('%s %s %s %s' % (self.id, self.phone, self.phone_ext, ret))
        #     raise gen(CODES.DOCTOR_REG_PHONE_EXT_ERROR)

    def get_doctor_replied_problems_count(self):
        """
        查询给定医生回答的问题的数目

        """
        from django.db import connection

        cursor = connection.cursor()
        SQL = "SELECT distinct problem_id FROM api_topicreply a WHERE doctor_id = '%s' and not exists(select 1 " \
              "from api_problem where id=a.problem_id and private_status!='0')" % self.id
        return cursor.execute(SQL)

    def get_doctor_item_list(self, has_all=False, tag_v3=False):
        """
        医生的tag案例
        :return:
        """
        if tag_v3:
            result = doctor_tagv3s_cache.get(self.id)
        else:
            result = doctor_tags_cache.get(self.id)

        item_list_raw = []
        item_list = []

        if not result:
            pass
        else:
            try:
                result = json.loads(result)
                item_list = result['item_list']
                item_list_raw = result['item_list_raw']
                total = 0
                if has_all:
                    for item in item_list_raw:
                        count = int(item["name"].split(" ")[1].replace(u"例",u''))
                        total += count
                    item_list_raw.insert(0,{"name": u"全部 {}例".format(total), "tag_id": ""})
                    item_list.append(u"全部")
            except:
                pass

        return (item_list, item_list_raw)

    def get_service_tags_distribution(self):
        try:
            return json.loads(doctor_service_tags_distribution_cache.get(str(self.id)))
        except:
            return []

    def get_doctor_service_num(self):
        return self.services.filter(is_online=True).count()

    def sell_amount_display(self):
        """
        预约数
        :return:
        """
        sell_amount = doctor_sell_amount_cache.get(self.id)
        if sell_amount is None:
            from api.models.service import Service
            if self.doctor_type == DOCTOR_TYPE.DOCTOR:
                sell_amount = sum([service.sell_amount_display for service in self.services.filter(is_online=True).only(
                    'fake_sold_num', 'id'
                )])
            else:
                sell_amount = 0
                services = Service.objects.filter(
                    doctor__hospital_id=self.hospital.id, doctor__is_online=True, is_online=True
                ).only('fake_sold_num', 'id', 'name')
                for service in services:
                    sell_amount += service.sell_amount_display
            doctor_sell_amount_cache.setex(self.id, 60 * 60, sell_amount)
        return sell_amount

    def get_hospital_service_num(self):
        if self.hospital:
            hospital_id = self.hospital.id
        else:
            service_num = 0
            return service_num

        service_num = 0
        try:
            result = hospital_doctor_service_cache.get(hospital_id)
            if result:
                result = json.loads(result)
                service_num = result['service_num']
        except:
            logging_exception()

        return service_num

    def get_rank_doctor_detail(self):
        res = self.doctor_detail()
        user= res['user']
        hospital= res['hospital']

        if self.doctor_type == DOCTOR_TYPE.OFFICER and self.hospital:
            # 解决医院底下医生有美购,但是医院机构管理者没有美购的情况
            service_num = self.get_hospital_service_num()
        else:
            service_num = self.get_doctor_service_num()

        lincence = self.get_doctor_lincence(self.title, service_num)

        return {
            'id':user.get('id'),
            'portrait':user.get('portrait'),
            'name':user.get('name'),
            'star':self.rate,
            'badges':self.badges(),
            'title_raw':'' if lincence['title_raw'] == '无职称' else lincence['title_raw'],
            'practice_time':self.practice_time,
            'hospital':hospital.get('name'),
            'show_v': lincence['show_v'],
            'diary_amount': self.share_diary_num, # 案例数
            'subscribe_num': self.sell_amount_display(),  # 预约数
        }

    def doctor_detail(self, user=None):
        """
        在医生列表中将doctor的信息转换成为医生信息
        @param self:
        @return:
        """
        if user:
            from social import SocialInfo
            social_info = SocialInfo(uid=user.id)
        from talos.models.topic import Problem
        problems = Problem.objects.filter(is_online=True, doctor_id=self.id)
        share_amount = problems.count()

        item_list, item_list_raw = self.get_doctor_item_list()
        result = {
            "user": {
                'id': self.id,
                'name': self.name,
                'user_id': self.user.id if self.user else None,
                'portrait': get_full_path(self.portrait),
                'title': DOCTOR_TITLE_TYPE.getDesc(self.title),
                'rate': self.rate,
                'introduction': self.introduction,
                'accept_private_msg': self.accept_private_msg,
                'accept_call': self.accept_call,
                'phone': PhoneService.get_phone_prefix(self.phone_ext),
                'phone_ext': self.phone_ext or '',
                'good_at': self.good_at,
                'doctor_type': self.doctor_type,
                'department': self.department,
                'doctor_phone': self.phone,
                'work_start_time': self.start_time.strftime('%H:%M:%S'),
                'work_end_time': self.end_time.strftime('%H:%M:%S'),
                'online_time': self.online_time.strftime('%Y-%m-%d')
            },
            'hospital': {
                'name': self.hospital.name if self.hospital else None,
                'id': self.hospital.id if self.hospital else None,
                'baidu_loc_lng': self.hospital.baidu_loc_lng if self.hospital else 0,
                'baidu_loc_lat': self.hospital.baidu_loc_lat if self.hospital else 0,
                'location': self.hospital.location if self.hospital else None,
                'desk_phone': self.hospital.desk_phone if self.hospital else None,
                'description': self.hospital.description if self.hospital else None,
                'city_name': self.hospital.city.name,
            },
            'share_amount': share_amount,
            'diary_amount': self.share_diary_num,
            'service_amount': self.services.filter(is_online=True).count(),
            "item_list": item_list,
            'item_list_raw': item_list_raw,
            "service_tags_distribution": self.get_service_tags_distribution(),
            'is_following': user and self.user and social_info.is_following_user(uid=self.user.id) or False,
            'reply_amount': self.get_doctor_replied_problems_count(),
            'accept_reserve': self.accept_reserve,
            'allow_hospital_agent': self.allow_hospital_agent,
            'is_online': self.is_online,
        }

        result.update(self.get_doctor_lincence(result['user']['title'], result['service_amount']))

        return result

    def get_doctor_tags(self):
        if doctor_search_tags_cache.get(self.id):
            return json.loads(doctor_search_tags_cache.get(self.id))
        return []

    def doctor_detail_v2(self, is_favored=False, need_intro=False, advertise_id=None, query="", services_size=None,case_dict=None):
        """
        在医生列表中将doctor的信息转换成为医生信息
        @param self:
        @return:
        """
        from search.utils.service import get_exterior_service_ids
        from search.utils.service import get_exterior_service_ids_extend
        try:
            province_id = self.hospital.city.province.id
        except:
            province_id = -1

        if self.doctor_type == DOCTOR_TYPE.OFFICER and self.hospital:
            # 解决医院底下医生有美购,但是医院机构管理者没有美购的情况
            service_num = self.get_hospital_service_num()
            items = hospital_search_tags_cache.get(self.hospital.id)
        else:
            service_num = self.get_doctor_service_num()
            items = doctor_search_tags_cache.get(self.id)

        lincence = self.get_doctor_lincence(self.title, service_num)

        try:
            hospital_scale = self.hospital.hospital_extra.get_scale_desc()
        except:
            hospital_scale = ''

        if advertise_id is not None:
            from api.models import AdvertiseManagement
            try:
                ad = AdvertiseManagement.objects.select_related('extend_tip').get(pk=advertise_id)
                extend_tips = ad.extend_tip.tip_name
            except AdvertiseManagement.DoesNotExist:
                extend_tips = ''
        else:
            extend_tips = ''

        award_name, is_special_skin = self.get_award_name_and_is_special_skin()
        result = {
            'id': self.id,
            "did": self.id,  # 不久将要废弃掉
            "doctor_id": self.id,
            "province_id": province_id,
            'city_id': self.hospital.city.id,
            "portrait": get_full_path(self.portrait), # 医生头像
            "accept_private_msg": self.accept_private_msg, # 是否接受私信
            "accept_call": self.accept_call,# 是否可以打电话
            "name": self.name, # 医生名字
            "rate": self.rate if self.doctor_type == DOCTOR_TYPE.DOCTOR else self.hospital and self.hospital.rate or self.rate, # 用户综合评分
            "phone_ext": self.phone_ext, # 400电话
            "department": self.department, # 科室
            "is_recommend": False,
            "dist": -1,
            "last_active_time": "",
            "good_at": self.good_at, # 擅长项目
            "hospital": self.hospital and self.hospital.name or '',
            "hospital_name": self.hospital and self.hospital.name or '',
            "hospital_id": self.hospital and self.hospital.id or '',
            "address": self.hospital and self.hospital.location or '',
            "lat": self.hospital and self.hospital.baidu_loc_lat or 0,
            "lng": self.hospital and self.hospital.baidu_loc_lng or 0,
            "is_favored": is_favored,
            'share_amount': self.share_diary_num, # 日记本统计案例数
            'items': json.loads(items) if items else [], # 医生搜索的tag相关
            'service_num': service_num, # 美购数量
            'doctor_type': self.doctor_type, # 医生类型
            'is_hospital': self.is_hospital,
            'hospital_type': self.hospital.hospital_type or '',
            'is_online': self.is_online,
            'subscribe_num': self.sell_amount_display(), # 预约数
            'operate_tags': self.operate_tag(), # 运营tags
            'cases': self.cases(case_dict), #
            # 7675 添加
            'badges': award_name,        # 名医大赏标签
            "is_special_appearance": is_special_skin,  # 名医大赏是否有特殊皮肤
            'display_tags': [],
            "introduction": self.introduction if need_intro else "", # 医生介绍
            "phone": PhoneService.get_phone_num(self.phone_ext) if self.phone_ext else "",
            "phone_hint": "直播医生电话" if self.phone_ext else "",
            'show_v': lincence['show_v'],
            'title': lincence['title'],
            'title_raw': lincence['title_raw'],
            'show_rating': lincence['show_rating'],
            'hospital_scale': hospital_scale, # 医院连锁
            'extend_tips': extend_tips,
            'practice_time': self.practice_time, # 执业多少年
            'user_id': self.user_id,
            'hospital_type': self.hospital.hospital_type if self.hospital else '0', # 医生所在医院的医院类型（民营or 公立)
            'store_classification': self.is_store_classification,
            # zhanghang注销 @2019-4-10
            # 'exterior_service_ids': get_exterior_service_ids(
            #     doctor_type=self.doctor_type, doctor_id=self.id, hospital_id=self.hospital_id, keywords=query
            # ),
        }
        # 搜索只需要2条
        _service_high_light = dict()
        if services_size:
            _exterior_service_ids, _service_high_light = \
                get_exterior_service_ids_extend(doctor_type=self.doctor_type,
                                                doctor_id=self.id,
                                                hospital_id=self.hospital_id,
                                                keywords=query,
                                                size=services_size)
        else:
            _exterior_service_ids = \
                get_exterior_service_ids(doctor_type=self.doctor_type,
                                         doctor_id=self.id,
                                         hospital_id=self.hospital_id,
                                         keywords=query)
        result.update({
            'exterior_service_ids': _exterior_service_ids,
            'highlight': _service_high_light
        })

        result['display_tags'] = self.format_display_tags(hospital_scale, result['badges'], result['operate_tags'])

        return result

    def get_doctor_lincence(self, title, service_num):
        """
            此方法只用于 大V是否展示、是否显示rating的判断
            若是取医生的lincence查看doctor.b_licences doctor.p_licences
        """
        result = {}
        try:
            business_partener = self.business_partener
        except:
            business_partener = False

        if business_partener and self.b_licences \
                and self.p_licences:
            show_v = True
            show_title = True
        elif business_partener:
            show_v = False
            show_title = False
        elif (not business_partener) and self.b_licences \
                and self.p_licences:
            show_v = False
            show_title = True
        else:
            show_v = False
            show_title = False

        # 没有关联美购的不显示
        if not self.services.filter(is_online=True).count():
            show_v = False

        # 兼容客户端 '1'表示True '0'表示False
        result['show_v'] = '1' if show_v and settings.SHOW_V else '0'
        result['title'] = DOCTOR_TITLE_TYPE.getDesc(title) if show_title and title != DOCTOR_TITLE_TYPE.EMPTY else ''
        result['title_raw'] = DOCTOR_TITLE_TYPE.getDesc(title)
        # 将医生职称改为 '' by lipeng 2017-07-28
        # result['title'] = ''
        # result['title_raw'] = ''

        result['show_rating'] = '1' if service_num and self.rate else '0'

        return result

    def to_dict(self):
        result = to_dict(self)
        return result

    def __unicode__(self):
        return self.name

    def data(self):
        _data = {
            "id": self.id,
            "name": self.name,
            "portrait": self.portrait,
            "title": self.title,
        }
        return _data

    def service_tag(self):
        tags = []
        services = self.services.all()
        for service in services:
            _tags = service.tags.filter(tag_type=TAG_TYPE.BODY_PART_SUB_ITEM)
            for tag in _tags:
                info = {'id': tag.id, 'name': tag.name}
                if info not in tags:
                    tags.append(info)
        return tags

    def operate_tag(self):
        tags = []
        for tag in self.tags.all():
            if tag.tag_type == TAG_TYPE.YUNYING and tag.is_online is True:
                tags.append({'id': tag.id, 'name': tag.name})
        return tags


    def get_can_sell_sku_ids(self, doctor_id=None, service_id=None):
        from api.models import Service
        if doctor_id:
            service_ids = Service.objects.filter(is_online=True, doctor_id=doctor_id).values_list('id', flat=True)
        else:
            service_ids = self.services.filter(is_online=True).values_list('id', flat=True)
        if service_id:
            service_ids = [service_id]

        sids_2_skuids = Service.get_service_ids_to_can_sell_item_ids(service_ids)

        sku_ids = []
        for k, v in sids_2_skuids.iteritems():
            for i in v:
                sku_ids.append(i)
        return sku_ids

    def can_create_topic(self):
        the_monday = get_monday()
        from talos.models.topic import Problem
        return Problem.objects.filter(
            user_id=self.user_id,
            created_time__gte=the_monday
        ).count() < 30

    def _licence_images(self, licence_type):
        """
        获取 资质/执业证书照片/医生医院照片等
        若是机构管理者则直接返回 hospital的 证书照片
        机构管理者和医生（即doctor_type） 是不允许改变的
        """
        if self.doctor_type == DOCTOR_TYPE.OFFICER:
            if not self.hospital_id:
                return []
            image_list = DoctorLicence.objects.filter(hospital_id=self.hospital_id, type=licence_type)
        else:
            image_list = DoctorLicence.objects.filter(doctor_id=self.id, type=licence_type)
        images = [item.image_url for item in image_list]
        return images

    @property
    def b_licences(self):
        """资格证"""
        return self._licence_images(DOCTOR_LICENCE_TYPE.BUSINESS)

    @property
    def p_licences(self):
        """执业证"""
        return self._licence_images(DOCTOR_LICENCE_TYPE.PRACTICE)

    @property
    def t_licences(self):
        return self._licence_images(DOCTOR_LICENCE_TYPE.TITLE)

    @property
    def personal_pictures(self):
        return self._licence_images(DOCTOR_LICENCE_TYPE.PERSONAL_PICTURE)

    @property
    def honor_pics(self):
        return self._licence_images(DOCTOR_LICENCE_TYPE.HOSPITAL_HONOR_PICTURE)

    def update_licence_images(self, b_licences, p_licences, t_licences=None, personal_pictures=None):
        """
        修改机构的资质/执业证书照片
        """
        self._update_licence_images(DOCTOR_LICENCE_TYPE.BUSINESS, b_licences)
        self._update_licence_images(DOCTOR_LICENCE_TYPE.PRACTICE, p_licences)
        if t_licences is not None and self.doctor_type == DOCTOR_TYPE.DOCTOR:
            self._update_licence_images(DOCTOR_LICENCE_TYPE.TITLE, t_licences)
        if personal_pictures is not None and self.doctor_type == DOCTOR_TYPE.DOCTOR:
            self._update_licence_images(DOCTOR_LICENCE_TYPE.PERSONAL_PICTURE, personal_pictures)

    def update_image_doctor(self, doctor_images):
        """
        更新照片
        :param doctor_images:{'image_type': image_list} eg:
        {DOCTOR_LICENCE_TYPE.DOCTOR_PERSONALIZED_PHOTO_ALBUM: ['1.png','2.png']}
        :return:
        """
        for key, value in doctor_images.iteritems():
            self._update_licence_images(key, value)

    def update_recommend_service(self, service_ids):
        """
        更新医生的美购推荐
        :param service_ids:
        :return:
        """
        from hippo.models import RecommendService
        old_services = set(RecommendService.objects.filter(doctor_id=self.id))
        new_services = set(RecommendService.objects.get_or_create(
                doctor_id=self.id, service_id=service_id
            )[0] for service_id in service_ids)
        for item in (old_services- new_services):
            item.delete()

    def _update_licence_images(self, licence_type, licences_images):
        if not licences_images:
            return

        if not self.hospital_id:
            raise Exception(u'需要设置医生的医院doctor_id is %s' % self.id)

        if self.doctor_type == DOCTOR_TYPE.OFFICER:
            old_images = set(DoctorLicence.objects.filter(
                hospital_id=self.hospital_id, type=licence_type
            ))
            new_images = set(DoctorLicence.objects.get_or_create(
                hospital_id=self.hospital_id, type=licence_type, image_url=item
            )[0] for item in licences_images)
        else:
            old_images = set(DoctorLicence.objects.filter(
                doctor_id=self.id, type=licence_type
            ))
            new_images = set(DoctorLicence.objects.get_or_create(
                doctor_id=self.id, type=licence_type, image_url=item
            )[0] for item in licences_images)

        for item in (old_images - new_images):
            item.delete()

    def hospital_pics(self):
        if self.hospital_id:
            organizations = OrganizationImage.objects.filter(hospital_id=self.hospital_id)
        else:
            organizations = OrganizationImage.objects.filter(doctor_id=self.id)
        images = [item.image_url for item in organizations]
        return images

    def update_hospital_pics(self, images):
        if self.doctor_type == DOCTOR_TYPE.OFFICER:
            # 只有机构管理者才能够修改 医院的实景图片
            from api.models.organization import OrganizationImage
            org_image = OrganizationImage.objects.filter(hospital_id=self.hospital_id)
            for url in images:
                OrganizationImage.objects.get_or_create(doctor_id=self.id, image_url=url, hospital_id=self.hospital_id)
            # 删除删除掉的条目
            org_image.filter(~Q(image_url__in=images)).delete()

    def doctor_account(self):
        from hippo.models.merchant import MerchantRelevance, MerchantAccount
        da, _ = MerchantAccount.objects.get_or_create(merchant_id=self.merchant.id)
        account = {
            'doctor_id': self.id,
            'status': da.status,
            'content': {
                'bank': da.bank,
                'account_name': da.account_name,
                'account_number': da.account_number,
                'account_type': da.account_type,
                'city_name': da.city_finance.name if da.city_finance else '',
                'z_bank': da.subbranch,
                'city_id': da.city_finance.id if da.city_finance else None,
            }
        }
        return account

    def extra(self):
        """
        医生的额外信息
        :return:
        """
        from hippo.models import Doctor_Extra
        extras = Doctor_Extra.objects.filter(doctor=self)
        if extras.exists():
            return extras.first()
        else:
            return None

    @property
    def extra_info(self):
        extra_res = self.extra()
        if extra_res:
            return {
                'professional_certificate_num': extra_res.professional_certificate_num,
                'professional_certificate_time': extra_res.professional_certificate_time.strftime('%Y-%m-%d') if
                extra_res.professional_certificate_time else None,
                'professional_certificate_time_float': get_timestamp(extra_res.professional_certificate_time) if
                extra_res.professional_certificate_time else None,

            }
        else:
            return None
    @property
    def practice_time(self):
        """
        执业多少年
        :return:
        """
        try:
            return self.doctor_extra.working_year
        except:
            return 0

    @property
    def personalized_photo_album(self):
        """
        个性化相册
        :return:
        """
        return self._licence_images(DOCTOR_LICENCE_TYPE.DOCTOR_PERSONALIZED_PHOTO_ALBUM)

    @property
    def personalized_label(self):
        """
        个性化标签
        :return:
        """
        from hippo.models import Doctor_Related_PersonalizedLabel
        labels = Doctor_Related_PersonalizedLabel.objects.filter(doctor=self)
        return [{
                    'id': label.personalized_label.id,
                    'name': label.personalized_label.name
                } for label in labels]

    @property
    def recommend_services(self):
        from hippo.models import RecommendService
        recomend_services_lists = RecommendService.objects.filter(
            doctor_id=self.id).values_list('service_id', flat=True)
        from api import Service
        services = Service.objects.filter(id__in=recomend_services_lists)
        return [{
                    'id': item.id,
                    'name': item.name
                } for item in services]

    @property
    def level_image(self):
        """
        医院等级照片
        :return:
        """
        return self._licence_images(DOCTOR_LICENCE_TYPE.HOSPITAL_LEVEL)

    @property
    def area_image(self):
        """
        租赁面积照片
        :return:
        """
        return self._licence_images(DOCTOR_LICENCE_TYPE.RETAIL_LEASE_CONTRACT)

    @property
    def inter_p_image(self):
        """
        跨省机构营业执照
        :return:
        """
        return self._licence_images(DOCTOR_LICENCE_TYPE.INTER_PROVINCE_CHAIN_HOSPITAL)

    @property
    def same_p_image(self):
        """
        同省机构营业执照
        :return:
        """
        return self._licence_images(DOCTOR_LICENCE_TYPE.SAME_PROVINCE_CHAIN_HOSPITAL)

    def can_edit_info(self):
        """
            获取可以编辑的信息
        """
        data = {
            'id': self.id,
            'name': self.name,
            'status': self.status,
            'doctor_type': self.doctor_type,
            'area_type': self.area_type,
            'portrait': self.portrait,
            'title': self.title,
            'department': self.department,
            'phone': self.phone,
            'assist_phone': self.assist_phone,
            'introduction': self.introduction,
            'good_at': self.good_at,
            'b_licences': self.b_licences,
            'p_licences': self.p_licences,
            't_licences': self.t_licences,
            'personal_pictures': self.personal_pictures,
            'professional_certificate_num': None,
            'professional_certificate_time': None,
            'personalized_photo_album': self.personalized_photo_album,
            'personalized_label': self.personalized_label,
            'recommend_services': self.recommend_services,
            'hospital_pics': self.hospital_pics(),
        }

        if self.extra_info:
            data.update(self.extra_info)
        return data

    @classmethod
    def is_person_doctor(cls, person_id):
        try:
            person = Person.objects.get(id=person_id)
            return cls.objects.filter(user=person.user_id).exists()
        except Person.DoesNotExist:
            return False

    def doctor_rate_star(self):
        rate = self.rate
        if rate - math.trunc(rate) >= 0.5:
            star = math.trunc(rate) + 0.5
        else:
            star = math.trunc(rate)

        return round(star, 1)

    @property
    def agreement_image(self):
        """合同照片"""
        return [item.image_url for item in DoctorAgreement.objects.filter(doctor_id=self.id)]

    def get_officer(self):
        """
        如果用户为机构机构管理者，返回机构管理者，
        不是则返回None
        """
        if not self.hospital_id:
            return None

        officer_query = Doctor.objects.filter(
            hospital_id=self.hospital_id,
            doctor_type=DOCTOR_TYPE.OFFICER,
        )
        if officer_query.exists():
            return officer_query[0]
        return None

    @property
    def is_officer(self):
        """
        判断当前医生是否为机构管理者
        """
        if self.get_officer() and self.is_merchant:
            return True
        return False

    @property
    def merchant_doctor(self):
        '''获取该医生对应商户的医生
        '''
        if self.is_merchant:
            # 该医生是商户
            return self

        if not self.allow_hospital_agent:
            # 既不是商户，也没有托管
            return None

        officer = self.get_officer()
        if officer and officer.is_merchant:
            return officer
        return None

    def all_doctor_ids(self):
        """
        如果为机构管理者，返回机构管理+它们底下的医生
        如果为普通商户，返回这个医生
        如果为机构管理者下的普通医生，返回这个医生
        """
        if not self.is_merchant:
            return [self.id]

        if self.is_officer:
            return [obj.id for obj in self.merchant_doctors()]
        else:
            return [self.id]

    def merchant_doctors(self):
        """
        获取该医生能管理的商户下的医生()
        如果是普通医生，则展示自己
        如果是机构管理者，该机构下面所受管理的并且未被标记为商户的医生
        :return:
        """
        if not self.is_merchant:
            return []
        doctors = [self]
        if self.doctor_type == DOCTOR_TYPE.OFFICER and self.hospital_id:
            others = Doctor.objects.filter(
                hospital_id=self.hospital_id,
                is_merchant=False,
                allow_hospital_agent=True,
            )
            doctors += [d for d in others]
        return doctors

    def get_merchant_doctors(self):
        """
        获取该医生能管理的商户下的医生
        如果是普通医生，则展示自己
        如果是机构管理者，该机构下面所受管理的并且未被标记为商户的医生
        :return:
        """
        doctors = self.merchant_doctors()
        if not doctors:
            doctors = [self]
        return [{
                    'doctor_id': d.id,
                    'doctor_name': d.name,
                    'user_id': d.user_id,
                    'portrait': d.portrait,
                    'doctor': d,
                } for d in doctors]

    @property
    def doctor_title_display(self):
        title_name = ''
        if self.title:
            title_name = '' if self.title == DOCTOR_TITLE_TYPE.EMPTY else DOCTOR_TITLE_TYPE.getDesc(self.title)
        return title_name

    def get_business_group(self):
        """
        关联商务组信息
        :return:
        """
        try:
            team = Team.objects.get(id=self.business_group)
            return {
                "id": team.id,
                "name": team.name
            }
        except:
            return None
    def get_doctor_base_info(self):
        """
        获取医生的基础信息
        :return:
        """
        return {
            "doctor_id": self.id,
            "name" : self.name,
            "hospital_id":self.hospital.id if self.hospital else '',
            "hospital_name" : self.hospital.name if self.hospital else '',
            "city_name" : self.hospital.city.name if self.hospital and self.hospital.city else '',
            "business": self.business_partener.username if self.business_partener else '',
            "business_group": self.get_business_group()["name"] if self.get_business_group() else '',
            "merchant_id": self.merchant.id if self.merchant else '',
            'merchant_doctor_id': self.merchant.doctor.id if self.merchant else ''
        }

    def get_doctor_detail(self):
        """
        获取医生的信息
        :return:
        """
        return {
            "doctor_id": self.id,
            "name": self.name,
            "hospital_id": self.hospital.id if self.hospital.id else '',
            "hospital_name": self.hospital.name if self.hospital else '',
            "title": DOCTOR_TITLE_TYPE.getDesc(self.title, defaultValue='无职称'),
            'portrait': get_full_path(self.portrait) or "https://pic.igengmei.com/topicimage/2019/12/31/a81b11ca6e-s",
            'practice_time': self.practice_time,  # 执业多少年
            'good_at': self.good_at
        }

    # def get_detail_v3(self):
    #     """
    #     医生主页医生数据
    #     :return:
    #     """
    #     data = {
    #         "name": self.name,
    #         "title": self.doctor_title_display,
    #         "badges": self.badges(),
    #     }

class DoctorLicence(models.Model):
    class Meta:
        app_label = 'doctor'
        db_table = 'doctor_doctorlicence'
        verbose_name = u'证书图片'
        verbose_name_plural = u'证书图片'

    # 证书要么是医生的，要么是医院的
    doctor = models.ForeignKey(Doctor, help_text=u"医生的证书", null=True, blank=True)
    hospital = models.ForeignKey(Hospital, help_text=u"医院的证书", null=True, blank=True)
    type = models.IntegerField(verbose_name=u'证书类型', choices=DOCTOR_LICENCE_TYPE)
    image_url = ImgUrlField(img_type=IMG_TYPE.DOCTOR, max_length=256, help_text=u"图片url")



class DoctorAgreement(models.Model):
    class Meta:
        app_label = 'api'
        db_table = 'api_doctoragreement'
        verbose_name = u'商务合同图片'
        verbose_name_plural = u'商务合同图片'

    doctor = models.ForeignKey(Doctor, help_text=u"医生注册")
    image_url = ImgUrlField(img_type=IMG_TYPE.DOCTOR, max_length=256, help_text=u"图片url")


class OrganizationImage(models.Model):
    class Meta:
        app_label = 'api'
        db_table = 'api_organization_image'
        verbose_name = u'机构图片'
        verbose_name_plural = u'机构图片'

    image_url = ImgUrlField(img_type=IMG_TYPE.ORGANIZATIONIMAGE, max_length=256, help_text=u"图片url")
    doctor = models.ForeignKey(Doctor, help_text=u"医生")
    hospital = models.ForeignKey(Hospital, help_text=u"医院")


class DoctorEditRecord(models.Model):
    """
        每次提交修改+审核(驳回或者通过)  合在一起只有一条记录
    """

    class Meta:
        app_label = 'doctor'
        db_table = 'doctor_doctoreditrecord'
        verbose_name = u'医生信息修改日志'
        verbose_name_plural = u'医生信息修改日志'

    doctor = models.ForeignKey(Doctor, help_text=u"医生")
    status = models.IntegerField(verbose_name=u'信息修改状态', choices=DOCTOR_INFO_STATUS, default=DOCTOR_INFO_STATUS.CHECKED)
    reject_reason = models.CharField(u'拒绝原因', max_length=100, blank=True, null=True)
    handler = models.ForeignKey(Person, help_text=u"处理人", blank=True, null=True)
    created_at = models.DateTimeField(default=timezone.now, verbose_name=u'记录时间')
    content = models.TextField(u'修改后信息内容')

    def data(self):
        content = json.loads(self.content)
        content['professional_certificate_num'] = content.get('professional_certificate_num', None)
        content['professional_certificate_time'] = content.get('professional_certificate_time', None)
        content['personalized_photo_album'] = content.get('personalized_photo_album', [])
        content['personalized_label'] = content.get('personalized_label', [])
        content['recommend_services'] = content.get('recommend_services', [])
        info = {
            'doctor_id': self.doctor_id,
            'status': self.status,
            'reject_reason': self.reject_reason,
            'created_at': get_timestamp_epoch(self.created_at),
            'content': content,
        }
        return info


class DoctorAccount(models.Model):
    class Meta:
        app_label = 'api'

    doctor = models.OneToOneField(Doctor, related_name='account')
    country = models.ForeignKey(Country, null=True, blank=True)
    province = models.ForeignKey(Province, null=True, blank=True)
    city = models.ForeignKey(City, null=True, blank=True)
    bank = models.CharField('开户银行', max_length=30)
    subbranch = models.CharField('支行/分行', max_length=100, null=True, blank=True)
    account_name = models.CharField('户名', max_length=100)
    account_number = models.CharField('账号', max_length=50)
    account_type = models.IntegerField('开户类型', choices=DOCTOR_ACCOUNT_TYPE, default=DOCTOR_ACCOUNT_TYPE.BANK)
    #  0 银行 1 支付宝
    status = models.IntegerField(verbose_name=u'信息修改状态', choices=DOCTOR_ACCOUNT_STATUS,
                                 default=DOCTOR_ACCOUNT_STATUS.CHECKED)
    city_finance = models.ForeignKey(FinanceCity, null=True, blank=True, verbose_name=u'城市(关联财务省市的表)')


class DoctorAccountRecord(models.Model):
    """
        医生账号结算 信息
        每次提交修改+审核(驳回或者通过)  合在一起只有一条记录
    """

    class Meta:
        app_label = 'doctor'
        db_table = 'doctor_doctoraccountrecord'
        verbose_name = u'医生结算账号修改日志'
        verbose_name_plural = u'医生结算账号修改日志'

    account = models.ForeignKey(DoctorAccount, help_text=u"医生结算账号")
    status = models.IntegerField(verbose_name=u'信息修改状态', choices=DOCTOR_ACCOUNT_STATUS,
                                 default=DOCTOR_ACCOUNT_STATUS.CHECKED)
    reject_reason = models.CharField(u'拒绝原因', max_length=100, blank=True, null=True)
    handler = models.ForeignKey(Person, help_text=u"处理人", blank=True, null=True)
    created_at = models.DateTimeField(default=timezone.now, verbose_name=u'记录时间')
    content = models.TextField(u'修改后信息内容')

    def data(self):
        info = {
            'doctor_id': self.account.doctor_id,
            'status': self.status,
            'reject_reason': self.reject_reason,
            'created_at': get_timestamp_epoch(self.created_at),
            'content': json.loads(self.content)['content'],
        }
        city_id = info['content'].get('city_id', None)
        if city_id:
            try:
                info['content']['city_name'] = FinanceCity.objects.get(id=city_id).name
            except:
                info['content']['city_name'] = ''

        else:
            info['content']['city_name'] = ''
        return info


class HospitalInfo(models.Model):
    class Meta:
        verbose_name = u'医院基础信息'
        app_label = 'api'

    hospital = models.OneToOneField(Hospital, related_name='hospital_baseinfo', verbose_name=u'关联的医院')
    hospital_level = models.CharField(max_length=20, blank=False, null=False, verbose_name=u'医院级别')
    hospital_area = models.CharField(max_length=20, blank=False, null=False, verbose_name=u'医院平米数')
    city_num = models.IntegerField(default=0, verbose_name=u'开设医院城市数')
    hospital_num = models.IntegerField(default=0, verbose_name=u'连锁医院开设数')
    operation_num = models.IntegerField(default=0, verbose_name=u'手术室数量')
    injection_num = models.IntegerField(default=0, verbose_name=u'注射室数量')
    laser_num = models.IntegerField(default=0, verbose_name=u'激光治疗室数量')
    major_doc = models.IntegerField(default=0, verbose_name=u'主任医师数量')
    vice_doc = models.IntegerField(default=0, verbose_name=u'副主任医师数量')
    main_doc = models.IntegerField(default=0, verbose_name=u'主治医师数量')
    in_doc = models.IntegerField(default=0, verbose_name=u'住院医师数量')
    other_doc = models.IntegerField(default=0, verbose_name=u'其他医师数量')
    reason = models.CharField(max_length=100, blank=True, null=True, verbose_name=u'拒绝原因')
    status = models.IntegerField(verbose_name='审核状态', choices=HOSPITAL_INFO_REVIEW, default=HOSPITAL_INFO_REVIEW.SUBMIT)
    created_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
    submit_time = models.DateTimeField(verbose_name='提交时间')

    def base_info(self):
        data = {}
        hospital_level = {}
        hospital_level['level'] = self.hospital_level
        level_images = self.get_pics(type=HOSPITAL_INFO_IMAGE.LEVEL)
        hospital_level['images'] = level_images
        hospital_area = {}
        hospital_area['area'] = self.hospital_area
        area_images = self.get_pics(type=HOSPITAL_INFO_IMAGE.AREA)
        hospital_area['images'] = area_images
        city_num = {}
        city_num['nums'] = self.city_num
        city_images = self.get_pics(type=HOSPITAL_INFO_IMAGE.CITY)
        city_num['images'] = city_images
        hospital_num = {}
        hospital_num['nums'] = self.hospital_num
        hospital_images = self.get_pics(type=HOSPITAL_INFO_IMAGE.CHAIN)
        hospital_num['images'] = hospital_images
        operation_num = {}
        operation_num['nums'] = self.operation_num
        operation_images = self.get_pics(type=HOSPITAL_INFO_IMAGE.OPERATING)
        operation_num['images'] = operation_images
        injection_num = {}
        injection_num['nums'] = self.injection_num
        injection_images = self.get_pics(type=HOSPITAL_INFO_IMAGE.INJECTION)
        injection_num['images'] = injection_images
        laser_num = {}
        laser_num['nums'] = self.laser_num
        laser_images = self.get_pics(type=HOSPITAL_INFO_IMAGE.LASER)
        laser_num['images'] = laser_images
        data['hospital_level'] = hospital_level
        data['hospital_area'] = hospital_area
        data['city_num'] = city_num
        data['hospital_num'] = hospital_num
        data['operation_num'] = operation_num
        data['injection_num'] = injection_num
        data['laser_num'] = laser_num
        data['major_doc'] = Doctor.objects.filter(hospital_id=self.hospital_id, allow_hospital_agent=True,
                                                  title=u'主任医师', is_online=True).count()
        data['vice_doc'] = Doctor.objects.filter(hospital_id=self.hospital_id, allow_hospital_agent=True,
                                                 title=u'副主任医师', is_online=True).count()
        data['main_doc'] = Doctor.objects.filter(hospital_id=self.hospital_id, allow_hospital_agent=True,
                                                 title=u'主治医师', is_online=True).count()
        data['in_doc'] = Doctor.objects.filter(hospital_id=self.hospital_id, allow_hospital_agent=True,
                                               title=u'住院医师', is_online=True).count()
        data['other_doc'] = Doctor.objects.filter(hospital_id=self.hospital_id, allow_hospital_agent=True,
                                                  is_online=True) \
            .exclude(title__in=[u'主任医师', u'副主任医师', u'主治医师', u'住院医师']).count()
        data['status'] = self.status
        data['reason'] = self.reason
        return data

    def update_pics(self, type, pics=[]):
        old_imgs = HospitalInfoLicenes.objects.filter(hospitalinfo_id=self.id, type=type)
        for url in pics:
            HospitalInfoLicenes.objects.get_or_create(
                hospitalinfo_id=self.id,
                image_url=url,
                type=type,
            )
        old_imgs.filter(~Q(image_url__in=pics)).delete()

    def get_pics(self, type):
        imgs = HospitalInfoLicenes.objects.filter(hospitalinfo_id=self.id, type=type)
        return [rp.image_url for rp in imgs]


class HospitalLicenes(models.Model):
    class Meta:
        verbose_name = u'医院基础信息图片'
        app_label = 'api'

    hospital = models.ForeignKey(Hospital, verbose_name=u'关联的医院')
    image_url = ImgUrlField(img_type=IMG_TYPE.HOSPITAL, max_length=256, help_text=u"图片url")
    type = models.IntegerField(verbose_name=u'图片类型', choices=HOSPITAL_INFO_IMAGE)


class HospitalInfoLicenes(models.Model):
    class Meta:
        verbose_name = u'医院基础信息图片'
        app_label = 'api'

    hospitalinfo = models.ForeignKey(HospitalInfo, verbose_name=u'关联的医院信息')
    image_url = ImgUrlField(img_type=IMG_TYPE.HOSPITAL, max_length=256, help_text=u"图片url")
    type = models.IntegerField(verbose_name=u'图片类型', choices=HOSPITAL_INFO_IMAGE)


class DoctorServiceRank(models.Model):
    class Meta:
        verbose_name = u'医生或机构美购排名'
        app_label = 'hippo'
        db_table = 'doctor_service_rank'
        unique_together = ('doctor', 'service_id')

    doctor = models.ForeignKey(Doctor, related_name='service_ranks', verbose_name="医生或机构ID")
    service_id = models.IntegerField(verbose_name="美购ID")
    rank = models.IntegerField(verbose_name="排名")

    @classmethod
    def get_cmp_max_rank_result(cls, doctor, rank):
        doctor_service_rank = cls.objects.filter(doctor=doctor).order_by('-rank').first()
        max_rank = doctor_service_rank.rank if doctor_service_rank else 0
        return rank - max_rank

    @classmethod
    def batch_delete_rank(cls, doctor_service_ranks):
        for dsr in doctor_service_ranks:
            result = cls.get_cmp_max_rank_result(dsr.doctor_id, dsr.rank)
            if result < 0:
                cls.objects.filter(
                    doctor=dsr.doctor_id, rank__gt=dsr.rank
                ).update(rank=F('rank') - 1)
            dsr.delete()


class DoctorDiaryRank(models.Model):
    class Meta:
        verbose_name = u'医生或机构日记本排名'
        app_label = 'hippo'
        db_table = 'doctor_diary_rank'
        unique_together = ('doctor', 'diary_id')

    doctor = models.ForeignKey(Doctor, related_name="diary_ranks", verbose_name="医生或机构ID")
    diary_id = models.IntegerField(verbose_name="日记本ID")
    rank = models.IntegerField(verbose_name="排名")

    @classmethod
    def get_cmp_max_rank_result(cls, doctor, rank):
        doctor_diary_rank = cls.objects.filter(doctor=doctor).order_by('-rank').first()
        max_rank = doctor_diary_rank.rank if doctor_diary_rank else 0
        return rank - max_rank

    @classmethod
    def batch_delete_rank(cls, doctor_diary_ranks):
        for ddr in doctor_diary_ranks:
            result = DoctorDiaryRank.get_cmp_max_rank_result(ddr.doctor_id, ddr.rank)
            if result < 0:
                DoctorDiaryRank.objects.filter(
                    doctor=ddr.doctor_id, rank__gt=ddr.rank
                ).update(rank=F('rank') - 1)
            ddr.delete()

class DoctorCard(models.Model):
    class Meta:
        verbose_name = u'医生/机构'
        app_label = 'api'
        db_table = 'api_doctor_card'

    doctor = models.ForeignKey(Doctor, verbose_name="医生或机构ID")
    card_url = models.CharField(max_length=255, verbose_name="卡片地址")
    gen_time = models.DateTimeField(auto_now_add=True, verbose_name="生成时间")


