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

from datetime import datetime
import math
from django.db.models import Sum, Case, When, IntegerField, F, Q
from django.db import transaction
from django.conf import settings
from django.db.models import Min

from ..tool.service_tool import Cleaner, count_pre_payment

from gm_types.gaia import SERVICE_REVIEW_TYPE, SERVICE_SELL_TYPE, DOCTOR_TYPE, VIDEO_CODE_STATUS, OPERTOR_REVIEW_TYPE
from gm_types.gaia import SERVICE_REVIEW_STATUS as REVIEW
from gm_types.ascle import SERVICE_REVIEW_LIST_TYPES
from gm_types.gaia import ORDER_STATUS, DOCTOR_SECKILL_APPLY_STATUS
from gm_types.ascle.types import SERVICE_ORDER_TYPE
from gm_upload.upload import get_video_upload_token

from api.models import Person, City, AuditAttrOptions
from api.models import Tag, AttrOptions, PeriodHospital
from api.models import ServiceRegister, ServiceRegisterItemKey, ServiceRegisterVideo
from api.models import Service, IMAGE_TYPE, UploadButton
from api.models import ServiceRegisterItem
from api.models.special import SpecialSeckillButton, DoctorSeckillApply, Special
from api.models import add_reviewrecord

from api.tool.user_tool import get_doctor_from_context
from hippo.models import Doctor
from search.utils.service import filter_service
from rpc.decorators import bind, bind_context
from rpc.decorators import list_interface
from rpc.tool.error_code import gen, CODES
from rpc.tool.dict_mixin import to_dict
from api.tool.datetime_tool import get_timestamp, get_timestamp_epoch
from api.tool.coupon_tool import skus_for_coupon
from api.tasks.service_task import set_water_mark_to_video_service

# TODO zhangyunyu
# from api.models import TopicImage
from talos.models.topic import TopicImage

html_cleaner = Cleaner(safe_attrs_only=False)


@bind('api/doctor/service/my')
@list_interface(offset_name='start_num', limit_name='count',
                element_model=Service)
def get_services_my(count=10, start_num=0, doctor_id=None):
    # TODO Deprecated since 1.5.0
    """
        @Deprecated, see 'doctor/service/list'
    """
    result = []

    filters = {}
    if doctor_id:
        filters['doctor_id'] = doctor_id
    service_ids = filter_service(offset=start_num, size=count, filters=filters)
    ids = service_ids['service_ids']
    services = Service.objects.filter(id__in=ids)

    for service in services:
        result.append({
            'id': service.id,
            'name': service.name,
            'gengmei_price': service.gengmei_price_display,
            'pre_payment_price': service.lowest_pre_payment_price,
            'sell_amount': service.real_sell_amount,
            'is_multiattribute': service.is_multiattribute,
        })
    return result


@bind_context('doctor/service/my', login_required=True)
@list_interface(offset_name='start_num', limit_name='count',
                element_model=Service)
def get_my_services(ctx, count=10, start_num=0):
    # TODO Deprecated since 1.6.0
    """
        ##获取医生美购
        Deprecated 1.6.0, see 'doctor/service/list'
    """
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)
    result = {
        'data': [],
        'total_count': 0,  # 总数
    }
    services = Service.objects.filter(doctor_id=doctor.id, is_online=True)
    services = services.order_by('end_time', '-start_time', 'ordering')
    result['total_count'] = services.count()
    for service in services[start_num:start_num + count]:
        result['data'].append({
            'id': service.id,
            'name': service.name,
            'image': service.image_header,
            'gengmei_price': service.gengmei_price_display,
            'pre_payment_price': service.lowest_pre_payment_price,
            'sell_amount': service.real_sell_amount,
            'is_multiattribute': service.is_multiattribute,
        })
    return result


@bind_context('doctor/service/case_list', login_required=True)
def get_service_cases(ctx, count=10, start_num=0):
    # TODO Deprecated since 1.6.0
    # todo 已废弃，不再维护 180314
    # todo 已废弃，不再维护 180314
    # todo 已废弃，不再维护 180314
    """
        ##获取医生 案例
    """
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)
    result = {
        'data': [],
        'total_count': 0,  # 总数
    }
    services = Service.objects.filter(doctor_id=doctor.id, is_online=True)
    services = services.order_by('end_time', '-start_time', 'ordering')

    num = 0
    for service in services:
        pre_images_count = TopicImage.objects.filter(
            topic__diary__service_id=service.id, topic__is_online=True,
            image_type=IMAGE_TYPE.PRE_OPERATION_IMAGE).count()
        post_images_count = TopicImage.objects.filter(
            topic__diary__service_id=service.id, topic__is_online=True,
            image_type=IMAGE_TYPE.POST_OPERATION_IMAGE).count()
        if pre_images_count and post_images_count:
            num += 1
            if start_num < num:
                result['data'].append({
                    'id': service.id,
                    'name': service.name,
                    'image': service.image_header,
                })
            if len(result['data']) == count:
                break
    return result


@bind('doctors/service_id/list')
def get_services_ids_by_doctor_ids(doctor_ids):
    """
        批量获取医生美购id
    """
    if not doctor_ids:
        return gen(CODES.DOCTOR_NOT_FOUND)
    services_ids = list(Service.objects.filter(doctor_id__in=doctor_ids).values_list('id', flat=True))
    return services_ids


@bind_context('doctor/service/list', login_required=True)
@list_interface(offset_name='start_num', limit_name='count',
                element_model=Service)
def get_doctor_services(ctx, doctor_id, count=10, start_num=0, is_online=None,
                        order_by=SERVICE_ORDER_TYPE.DEFAULT):
    """
        获取医生美购
        is_online: True or False
    """
    if not doctor_id:
        return gen(CODES.DOCTOR_NOT_FOUND)
    result = {
        'data': [],
        'total_count': 0,  # 总数
    }
    if isinstance(doctor_id,list):
        services=Service.objects.filter(doctor_id__in=doctor_id)
    else:
        services = Service.objects.filter(doctor_id=doctor_id)
    if is_online is not None:
        services = services.filter(is_online=is_online)

    if order_by == SERVICE_ORDER_TYPE.ONLIENE_TIME_ASC:
        services = services.order_by('start_time')
    elif order_by == SERVICE_ORDER_TYPE.ONLINE_TIME_DESC:
        services = services.order_by('-start_time')
    elif order_by == SERVICE_ORDER_TYPE.IS_ONLINE_ASC:
        services = services.order_by('is_online')
    elif order_by == SERVICE_ORDER_TYPE.IS_ONLINE_DESC:
        services = services.order_by('-is_online')
    elif order_by in [SERVICE_ORDER_TYPE.ORDER_NUM_ASC,
                      SERVICE_ORDER_TYPE.ORDER_NUM_DESC]:
        # 按 成单量排序
        services = services.annotate(
            real_sell_amount_for_doctor=Sum(
                Case(
                    When(order__status__in=Service.order_amount_status_set,
                         then=1),
                    default=0,
                    output_field=IntegerField(),
                )
            )
        )
        if order_by == SERVICE_ORDER_TYPE.ORDER_NUM_ASC:
            services = services.order_by('real_sell_amount_for_doctor')
        else:
            services = services.order_by('-real_sell_amount_for_doctor')
    elif order_by in [SERVICE_ORDER_TYPE.USED_NUM_ASC,
                      SERVICE_ORDER_TYPE.USED_NUM_DESC]:
        # 按 验证单量排序
        services = services.annotate(
            used_amount_for_doctor=Sum(
                Case(
                    When(order__status__in=ORDER_STATUS.USED, then=1),
                    default=0,
                    output_field=IntegerField(),
                )
            )
        )
        if order_by == SERVICE_ORDER_TYPE.USED_NUM_ASC:
            services = services.order_by('used_amount_for_doctor')
        else:
            services = services.order_by('-used_amount_for_doctor')
    elif order_by in [SERVICE_ORDER_TYPE.REFUNDED_NUM_ASC,
                      SERVICE_ORDER_TYPE.REFUNDED_NUM_DESC]:
        # 按 退款单量排序
        services = services.annotate(
            refunded_amount_for_doctor=Sum(
                Case(
                    When(order__status__in=ORDER_STATUS.REFUNDED, then=1),
                    default=0,
                    output_field=IntegerField(),
                )
            )
        )
        if order_by == SERVICE_ORDER_TYPE.REFUNDED_NUM_ASC:
            services = services.order_by('refunded_amount_for_doctor')
        else:
            services = services.order_by('-refunded_amount_for_doctor')
    else:
        # 默认排序
        services = services.order_by('end_time', '-start_time', 'ordering')

    result['total_count'] = services.count()
    for service in services[start_num:start_num + count]:
        # for service in services:
        real_order_amount = service.real_order_amount_v2  # 成单量

        sk_info = service.get_lowest_price_seckill_info()

        item = {
            'id': service.id,
            'name': service.name,
            'image': service.image_header,
            'short_description': service.short_description,
            'gengmei_price': service.gengmei_price_display,
            'pre_payment_price': service.lowest_pre_payment_price,
            'real_order_amount': real_order_amount,
            'sell_amount': service.real_sell_amount_v2,
            'sell_amount_display': service.sell_amount_display,
            'used_amount': service.used_amount,
            'refunded_amount': service.refunded_amount,
            'is_multiattribute': service.is_multiattribute,
            'original_price': service.original_price,
            'is_seckill': True if sk_info else False,
            'is_online': service.is_online,
            'online_time': get_timestamp(service.start_time),
            'refunded_rate': u'0%',
            'service_type': service.service_type,
        }
        # 退款率＝退款数量／成单量
        if real_order_amount:
            item['refunded_rate'] = u'{}%'.format(
                service.refunded_amount * 100 // real_order_amount)

        result['data'].append(item)

    return result


@bind_context('doctor/service/service_index', login_required=True)
def service_index(ctx, doctor_id):
    """
    首页美购销量
    :param ctx:
    :param doctor_id:
    :return:
    """
    services = Service.objects.filter(doctor_id=doctor_id, is_online=True)
    services = services.annotate(
        real_sell_amount_for_doctor=Sum(
            Case(
                When(order__status__in=Service.order_amount_status_set,
                     then=1),
                default=0,
                output_field=IntegerField(),
            )
        )
    ).order_by('-real_sell_amount_for_doctor')
    result = []
    for s in services:
        item = {}
        item['service_name'] = s.name
        item['sales'] = s.real_sell_amount_for_doctor
        result.append(item)
    return result


def get_tag_template(tag):
    result = []
    for attr in tag.tagattr_set.filter(is_online=True):
        options = list(
            attr.attroptions_set.filter(is_online=True).values('name', 'id',
                                                               'is_online'))
        if len(options) != 0:
            result.append({
                'id': attr.id,
                'name': attr.name,
                'is_online': attr.is_online,
                'options': options
            })
    return {'attr_options': result, 'name': tag.name, 'video_token': get_video_upload_token()}


@bind_context('doctor/service/settings', login_required=True)
def service_settings(ctx, service_type=SERVICE_SELL_TYPE.NORMAL):
    if service_type == SERVICE_SELL_TYPE.FENGXIANGGOU:
        setting = settings.SERVICE_FENGXIANGGOU_SETTING.copy()
    else:
        setting = settings.SERVICE_SETTING.copy()
    setting['default_tag_attr_id'] = settings.DEFAULT_TAG_ATTR_ID
    return setting


@bind_context('api/service/template', login_required=True)
def get_doctor_service_template(ctx, tag_id):
    """
        获取tag对应的模板
    """
    if not tag_id:
        return gen(CODES.PARAMS_INCOMPLETE)

    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)
    tag = Tag.objects.get(id=tag_id, is_online=True)
    return get_tag_template(tag)


def __gen_service_register_detail(service_registers):
    """私有方法,service_registers中特殊的计算字段(最新更新时间)."""

    result = []
    register_ids = []
    for service_register in service_registers:
        result.append({
            'id': service_register.id,
            'short_description': service_register.short_description,
            'status': REVIEW.UNDER_REVIEW if service_register.is_register and \
                                             service_register.review_status == REVIEW.PASS else \
                service_register.review_status,
            'is_special': service_register.is_specialreview,
            'service_id': service_register.service.id if service_register.service else None,
            'is_online': service_register.service.is_online if service_register.service else None,
            'service_name': service_register.name,
            'service_type': service_register.service_type,
            'lastest_time': get_timestamp(service_register.lastest_time),
            'gengmei_price': 0,
            'pre_payment_price': 0,
            # 'locked': service_register.service.is_lock if service_register.service else False,
            'locked': False,  # 维度降低到SKU，换个字段
            'has_sku_lock': service_register.service.has_sku_lock if service_register.service else False,
            'is_draft': service_register.is_draft,
            'doctor_id': service_register.doctor.id,
            'doctor_name': service_register.doctor.name,
            'activity_status': service_register.get_activity_status()
        })
        register_ids.append(service_register.id)

    # 为了一次性查出每一个美购的最小价
    min_prices = ServiceRegisterItem.objects.filter(service_register__in=register_ids,
                                                    is_online=True,
                                                    is_delete=False).annotate(min_gengmei_price=Min('gengmei_price'),
                                                                              min_pre_payment_price=Min(
                                                                                  'pre_payment_price_int')).values(
        'service_register_id', 'min_gengmei_price', 'min_pre_payment_price')
    for register in result:
        for min_price in min_prices:
            if register['id'] == min_price['service_register_id']:
                register['gengmei_price'] = min_price['min_gengmei_price']
                register['pre_payment_price'] = min_price['min_pre_payment_price']
                break
    return result

@bind_context('doctor/service/review', login_required=True)
@list_interface(offset_name='start_num', limit_name='count', element_model=ServiceRegister)
def get_doctor_service_register(ctx, review_type, ask_all_counts=False,
                                keyword=None, doctor_ids=None,
                                count=10, start_num=0, service_type=None):
    """
    通过type确定 filter,处理是否需要所有总数,是否需要关键词过滤
    :type
    """
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)
    # 确定filter
    type2filters = {
        SERVICE_REVIEW_LIST_TYPES.ALL: {
        },
        SERVICE_REVIEW_LIST_TYPES.UNDER_PASS: {
            'is_register': True,
        },
        SERVICE_REVIEW_LIST_TYPES.ONLINE: {
            'is_register': False,
            'service__is_online': True,
        },
        SERVICE_REVIEW_LIST_TYPES.OFFLINE: {
            'is_register': False,
            'service__is_online': False,
        },
    }

    # 获得总数
    def get_counts(types, keyword, service_type=None):
        """获取总数的辅助方法"""
        result = []
        for t in types:
            c = get_register_query(t, keyword, service_type).count()
            result.append(c)
        return result

    def get_register_query(review_type, keyword, service_type=None):
        filters = type2filters[review_type]
        if service_type or service_type in [0, '0']:
            filters['service_type'] = service_type
        # 过滤关键字
        if keyword is not None:
            filters['short_description__contains'] = keyword
        services = ServiceRegister.objects.filter(doctor__in=doctor_ids or doctor, doctor_can_see=True, **filters)
        return services

    result = {}
    if ask_all_counts:
        result['counts'] = get_counts(
            sorted([i for i, _ in SERVICE_REVIEW_LIST_TYPES]), keyword, service_type)
    else:
        result['counts'] = get_counts((review_type,), keyword, service_type)

    services = get_register_query(review_type, keyword, service_type=service_type)
    services = services.annotate(
        lastest_time=Case(When(Q(last_submit_time__gte=F('last_review_time')) | Q(last_review_time__isnull=True),
                               then=F('last_submit_time')),
                          When(Q(last_review_time__gt=F('last_submit_time')) | Q(last_submit_time__isnull=True),
                               then=F('last_review_time'))),
    ).select_related("service").order_by("-lastest_time")
    # 格式化返回
    result['services'] = __gen_service_register_detail(services[start_num:start_num + count])
    return result


@bind_context('doctor/service/offline', login_required=True)
def doctor_service_offline(ctx, doctor_ids, service_register_id):
    """
        让一个美购下线,先更改service_register 状态,
        然后add_reviewrecord对比service和service_register给出描述.
    """
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)

    register = ServiceRegister.objects.get(id=service_register_id, doctor_id__in=doctor_ids,
                                           service__is_online=True)
    if register.review_status in (
            REVIEW.UNDER_REVIEW,
            REVIEW.UNDER_OFFLINE,
            REVIEW.SPECIAL_UNDER_REVIEW):
        return gen(CODES.NO_OFFLINE)

    # 在线美购被锁不能下线
    if register.service and register.service.has_sku_lock:
        return gen(CODES.NO_OFFLINE)

    register.review_status = REVIEW.UNDER_OFFLINE
    register.last_submit_time = datetime.now()
    register.save()

    person_id = register.user.person.id
    add_reviewrecord(register, person_id, review_type=SERVICE_REVIEW_TYPE.OFFLINE)


def add_item_data(items, is_seckill, register):
    # 区别 纷享购 取不同的配置
    if register.service_type == SERVICE_SELL_TYPE.FENGXIANGGOU:
        s_setting = settings.SERVICE_FENGXIANGGOU_SETTING.copy()
    else:
        s_setting = settings.SERVICE_SETTING.copy()

    seckill_default_discount = s_setting['seckill_default_discount']
    discount = s_setting['discount']
    pre_payment_price = s_setting['pre_payment_price']
    flag = False
    # 与产品确认，这部分逻辑废弃
    # if is_seckill:
    #     seckill = register.upload_button
    #     discount = seckill.discount if seckill else seckill_default_discount
    for item in items:
        item['stock_add_num'] = item.get('stock_add_num', register.add_num)  # 兼容先上gaia后上ascle,上线删除
        if item.get('id'):
            ritem = ServiceRegisterItem.objects.get(id=item.get('id'))
            if ritem.serviceitem:
                info = ritem.serviceitem.get_current_price_info()
                if ritem.serviceitem.can_modify_price:
                    # 无活动时改大需要审核
                    if not info.get('selling_rule', None):
                        if info['gengmei_price'] < item['gengmei_price']:
                            flag = True
                    # 任何情况改小需要审核
                    if info['gengmei_price'] > item['gengmei_price']:
                        flag = True
                if ritem.gengmei_price == item['gengmei_price']:
                    # 更美价相同则不对这条数据操作
                    continue
        if register.service_type == SERVICE_SELL_TYPE.FENGXIANGGOU:
            item['discount'] = int(math.ceil(item['gengmei_price'] * discount / 100.00))
            item['pre_payment_price'] = pre_payment_price
            # 产品确认过 向下取整
            pre_price = int(item['gengmei_price'] * pre_payment_price / 100)
            item['pre_payment_price_int'] = pre_price
        else:
            price_data = count_pre_payment(item['gengmei_price'])
            item['discount'] = price_data['discount']
            item['pre_payment_price'] = price_data['pre_payment_price']
            item['pre_payment_price_int'] = price_data['pre_payment_price_int']
    return items, flag


@bind_context('doctor/service/register', login_required=True)
def register_detail(ctx, register_id):
    doctor = get_doctor_from_context(ctx)
    try:
        register = ServiceRegister.objects.get(id=register_id)
    except ServiceRegister.DoesNotExist:
        return gen(CODES.NO_SERVICE_REGISTER)

    if register.project_type:
        project_type = register.project_type.id
        project_name = register.project_type.name
        tag_attr = get_tag_template(register.project_type)

    else:
        project_type, project_name, tag_attr = '', '', {'attr_options': []}

    def item_info(item):
        item_dict = to_dict(item)
        opt = ServiceRegisterItemKey.objects.filter(serviceregisteritem=item)
        item_dict['option_ids'] = [to_dict(x.serviceregisterattroption) for x in opt]
        item_dict['sku_stock'] = item.serviceitem.sku_stock if item.serviceitem else 0
        item_dict['is_lock'] = item.serviceitem.is_lock if item.serviceitem else False

        item_dict['option_ids'] = []
        for x in opt:
            serviceregisterattroption = to_dict(x.serviceregisterattroption)
            auditattroptions = AuditAttrOptions.objects.filter(serviceregisteritem=x.serviceregisteritem).order_by('created_time').first()
            if auditattroptions:
                serviceregisterattroption['name'] = auditattroptions.name
            item_dict['option_ids'].append(serviceregisterattroption)

        if item.serviceitem:
            info = item.serviceitem.get_current_price_info()
            item_dict['show_dialog'] = False if info['gengmei_price'] == item.gengmei_price else True
            item_dict['now_price'] = info['gengmei_price']
            item_dict['now_pre_payment'] = info['pre_payment_price']
            item_dict['price_start_time'] = get_timestamp_epoch(info['selling_rule']['start_time']) \
                if info.get('selling_rule') else ''
            item_dict['price_end_time'] = get_timestamp_epoch(info['selling_rule']['end_time']) \
                if info.get('selling_rule') else ''
            item_dict['activity_name'] = info['selling_rule']['name'] \
                if info.get('selling_rule') else ''
            item_dict['now_stock'] = info['sale_limit']
        else:
            item_dict['show_dialog'] = False
            item_dict['now_price'] = 0
            item_dict['now_pre_payment'] = 0
            item_dict['price_start_time'] = ''
            item_dict['price_end_time'] = ''
            item_dict['activity_name'] = ''
            item_dict['now_stock'] = 0
        try:
            city_id = item_dict.pop('city')
            if city_id:
                item_dict['city_name'] = item.city.name
                item_dict['city_id'] = item.city_id
        except:
            pass
        return item_dict

    def get_register_header():
        item = register.items.filter(is_delete=False).first()
        if not item:
            return None
        keys = ServiceRegisterItemKey.objects.filter(serviceregisteritem=item)
        return [to_dict(x.serviceregisterattroption.tag_attr) for x in keys]

    def is_seckill():
        if register.service:
            return not register.service.is_multiattribute
        return bool(register.upload_button)

    try:
        reason = register.servicereviewrecord_set.latest('created_time').reason
    except:
        # 美购老数据可能没有 record
        reason = ''
    if register.upload_button:
        seckill_discount = register.upload_button.discount
    else:
        if is_seckill():
            seckill_discount = settings.SERVICE_SETTING['seckill_default_discount']
        else:
            seckill_discount = None

    if register.service_type == SERVICE_SELL_TYPE.FENGXIANGGOU:
        pre_payment_price = settings.SERVICE_FENGXIANGGOU_SETTING['pre_payment_price']
    else:
        pre_payment_price = settings.SERVICE_SETTING['pre_payment_price']
    hasvideo = ServiceRegisterVideo.objects.filter(serviceregister_id=register.id).exists()
    if hasvideo:
        video_info = ServiceRegisterVideo.objects.get(serviceregister_id=register.id).get_video_info()
    items_ = [item_info(x) for x in register.items.filter(is_delete=False)]
    result = {
        'id': register.id,
        'service_name': register.name,
        'short_description': register.short_description,
        'service_id': register.service.id if register.service else None,
        'start_time': get_timestamp_epoch(register.start_time),
        'end_time': get_timestamp_epoch(register.end_time),
        'reservation': register.reservation,
        'total_num': register.total_num,  # 废弃, 上线后可删除, @张晓林
        'add_num': register.add_num,  # 废弃,上线后可删除, @张晓林
        'image_header': register.image_header,
        'photo_details': register.photo_details,
        'project_type': project_type,
        'project_name': project_name,
        'tag_attr': tag_attr,
        'seckill_discount': seckill_discount,
        'pre_payment_price': pre_payment_price,
        'attr_header': get_register_header(),
        'is_seckill': is_seckill(),
        'is_specialreview': register.is_specialreview,
        'review_status': REVIEW.UNDER_REVIEW if register.is_register and \
                                                register.review_status == REVIEW.PASS else \
            register.review_status,
        'turn_down_reason': reason,
        'items': items_,
        'record_info': register.record_info(with_operator_name=False),
        'have_extra_pay': register.have_extra_pay,
        'extra_pay_info': register.extra_pay_info,
        'image_bigpic': register.image_bigpic,
        'supplement_images': register.get_supplement_images(),
        'recommend_services': register.get_recommend_services(),
        'service_type': register.service_type,
        'video_token': get_video_upload_token(),
        'video_pic': video_info['video_pic'] if hasvideo else '',
        'video_url': video_info['video_url'] if hasvideo else '',
        'doctor_name': register.doctor.name,
        'doctor_id': register.doctor.id,
        'reject_reason': register.servicereviewrecord_set.order_by('-created_time')[0].reason if register.servicereviewrecord_set.order_by('-created_time') else None
    }
    try:
        if register.service_type == 3:
            cities = []
            item_names = []
            for item in items_:
                city = {}
                city['city_id'] = item['city_id']
                city['city_name'] = item['city_name']
                cities.append(city)
            #     option_ids = item.get('option_ids', None)
            #     if option_ids:
            #         item_names.append(option_ids.get('name', None))
            result.update(cities=cities)
            return result
    except:
        pass
    return result


@bind_context('doctor/service/seckill_info')
def get_seckill_info(ctx):
    """
        获取秒杀相关配置信息
    """
    now = datetime.now()
    seckill = UploadButton.objects.filter(start_show_time__lt=now,
                                          end_show_time__gt=now).first()
    if seckill:
        data = to_dict(seckill)
        t = ['start_sell_time', 'end_sell_time']
        data.update({x: get_timestamp_epoch(getattr(seckill, x)) for x in t})
        return data


@bind_context('doctor/service/register/create', login_required=True)
def register_create(ctx, data, applier, explanation=None):
    with transaction.atomic():
        # doctor = get_doctor_from_context(ctx)
        doctor = Doctor.objects.get(id=data.pop('doctor_id'))
        tag = Tag.objects.get(id=data['project_type'])
        is_seckill = data['is_seckill']
        is_draft = data.get('is_draft', False)

        is_specialreview = True if data.get('is_specialreview') else False
        if is_draft:
            review_status = REVIEW.DRAFT
        elif is_specialreview:
            review_status = REVIEW.SPECIAL_UNDER_REVIEW
        else:
            review_status = REVIEW.UNDER_REVIEW

        if applier:
            applier = Person.objects.get(id=applier)
        else:
            applier = doctor.user.person

        now = datetime.now()
        # 创建美购申请
        if data.get('service_type', SERVICE_SELL_TYPE.NORMAL) == 3:
            name = u'【{}】{}'.format(doctor.name, tag.name)
        else:
            name = u'【{}@{}】{}'.format(doctor.hospital.city.name, doctor.name, tag.name)
        kwargs = {
            'name': name,
            'user': applier.user,
            'doctor': doctor,
            'reservation': data['reservation'],
            'start_time': datetime.fromtimestamp(data['start_time']),
            'end_time': datetime.fromtimestamp(data['end_time']),
            'photo_details': html_cleaner.clean_html(data['photo_details']) if data['photo_details'] else '',
            'project_type': tag,
            'short_description': data['short_description'],
            'image_header': data['image_header'],
            'is_specialreview': is_specialreview,
            'review_status': review_status,
            'last_submit_time': now,
            'total_num': 0,
            'is_draft': is_draft,
            'is_stage': PeriodHospital.objects.filter(hospital=doctor.hospital, default_online=True).exists(),
            'add_num': data.get('add_num', 0),  # TODO: 上线之后删掉
            'have_extra_pay': data.get('have_extra_pay', False),
            'extra_pay_info': data.get('extra_pay_info'),
            'image_bigpic': data.get('image_bigpic'),
            'service_type': data.get('service_type', SERVICE_SELL_TYPE.NORMAL),
            'merchant_id': data.get('merchant_id')
        }
        if is_seckill:
            kwargs['upload_button'] = UploadButton.objects.filter(
                start_show_time__lt=now, end_show_time__gt=now).first()
            kwargs['name'] = kwargs['upload_button'].button_prefix + kwargs['name']

        register = ServiceRegister.objects.create(**kwargs)

        # 保存关联图片和推荐美购
        register.update_supplement_images(data.pop('supplement_images', []))
        register.update_recommend_services(data.pop('recommend_services', []))

        items, flag = add_item_data(data['items'], is_seckill, register)
        # 创建多属性
        if is_seckill:
            # 秒杀美购
            item = items[0]
            item['key'] = ''  # 秒杀没有标识符 @lipeng
            item['service_register'] = register
            item.pop('option_ids', None)
            ritem = ServiceRegisterItem.objects.create(**item)
            opt = AttrOptions.objects.create(
                tag_attr_id=settings.DEFAULT_TAG_ATTR_ID,
                name=tag.name, is_online=True)
            ServiceRegisterItemKey.objects.create(
                serviceregisteritem=ritem, serviceregisterattroption=opt)
        else:
            if tag.tagattr_set.filter(is_online=True).exists():
                # 标准美购
                for item in items:
                    option_ids = item.pop('option_ids')
                    item['service_register'] = register
                    item['key'] = '-'.join(map(str, option_ids))
                    ritem = ServiceRegisterItem.objects.create(**item)
                    for opt in option_ids:
                        ServiceRegisterItemKey.objects.create(
                            serviceregisteritem=ritem,
                            serviceregisterattroption_id=opt)
            else:
                # 非标准美购
                for item in items:
                    name = item.pop('project_name')
                    opt = AttrOptions.objects.create(
                        tag_attr_id=settings.DEFAULT_TAG_ATTR_ID,
                        name=name, is_online=True)
                    item['service_register'] = register
                    item['key'] = str(opt.id)
                    ritem = ServiceRegisterItem.objects.create(**item)
                    ServiceRegisterItemKey.objects.create(
                        serviceregisteritem=ritem, serviceregisterattroption=opt)
    video_url = data['video_url'] if data.get('video_url') else ''
    video_pic = data['video_pic'] if data.get('video_pic') else ''
    if video_url != '' or video_pic != '':
        if video_url != '':
            video_url = ServiceRegisterVideo.cleaned_video_url(video_url)
        video = ServiceRegisterVideo()
        video.serviceregister_id = register.id
        video.video_url = video_url
        video.video_pic = video_pic
        video.save()
        set_water_mark_to_video_service.delay(video.id)
    if is_draft:
        return None

    review_type = SERVICE_REVIEW_TYPE.ORDINARY
    if data['is_specialreview']:
        review_type = SERVICE_REVIEW_TYPE.SPECIAL
    return add_reviewrecord(register, applier.id, review_type=review_type, explanation=explanation)


@bind_context('doctor/service/register/edit', login_required=True)
def register_edit(ctx, register_id, data, applier, explanation=None):
    with transaction.atomic():
        # doctor = get_doctor_from_context(ctx)
        doctor = Doctor.objects.get(id=data['doctor_id'])
        register = ServiceRegister.objects.get(id=register_id)
        tag = Tag.objects.get(id=data['project_type'])
        # tag = register.project_type
        is_seckill = data['is_seckill']

        if register.review_status in (
                REVIEW.UNDER_REVIEW,
                REVIEW.SPECIAL_UNDER_REVIEW,
                REVIEW.UNDER_OFFLINE):
            return gen(CODES.NO_EDIT)

        # 美购被锁不能编辑
        # if register.service and register.service.is_lock:
        #    return gen(CODES.NO_EDIT)

        if applier:
            applier = Person.objects.get(id=applier)
        else:
            applier = doctor.user.person

        # 更改register 数值
        modify_items = [
            'short_description', 'start_time', 'end_time', 'reservation',
            'image_header', 'photo_details', 'is_specialreview', 'is_draft',
            'have_extra_pay', 'extra_pay_info', 'image_bigpic', 'doctor_id',
        ]
        for name in modify_items:
            pre = getattr(register, name)
            new = data.get(name)
            if name in {'start_time', 'end_time'}:
                new = datetime.fromtimestamp(new)
            elif name in {'photo_details'}:
                new = html_cleaner.clean_html(new) if new else ''
            if new != pre:
                setattr(register, name, new)
        if register.service_type == 3:
            setattr(register, 'name', u'【{}】{}'.format(doctor.name, tag.name))
        else:
            setattr(register, 'name', u'【{}@{}】{}'.format(doctor.hospital.city.name, doctor.name, tag.name))
        # TODO, 上线后删掉
        register.add_num = data.get('add_num', 0)

        # 编辑后, 若不是保存草稿 状态是要改的
        if not data.get('is_draft'):
            if data['is_specialreview']:
                register.review_status = REVIEW.SPECIAL_UNDER_REVIEW
            else:
                register.review_status = REVIEW.UNDER_REVIEW

        register.last_submit_time = datetime.now()

        # 保存关联图片和推荐美购
        image_urls = data.pop('supplement_images', [])
        register.update_supplement_images(image_urls)
        register.update_supplement_images_order(image_urls)
        register.update_recommend_services(data.pop('recommend_services', []))

        items, flag = add_item_data(data['items'], is_seckill, register)
        if flag:
            register.operator_review_type = OPERTOR_REVIEW_TYPE.WATI_REVIEW
        register.project_type = tag
        register.save()
        if is_seckill:
            # 秒杀更改
            item = items[0]
            item['key'] = ''  # 秒杀没有标识符 @lipeng
            item_id = item.pop('id')
            item.pop('is_online')
            sitem = ServiceRegisterItem.objects.filter(id=item_id)
            sitem.update(**item)
        else:
            # 这次编辑保留了哪些item
            saved_items = []
            if tag.tagattr_set.filter(is_online=True).exists():
                # 标准美购
                for item in items:
                    item_id = item.pop('id', None)
                    if item_id is None:
                        # 新增数据
                        option_ids = item.pop('option_ids')

                        item['key'] = '-'.join(map(str, option_ids))
                        item['service_register'] = register
                        ritem = ServiceRegisterItem.objects.create(**item)
                        saved_items.append(ritem)

                        # 新建价格数据，添加维度属性
                        for opt in option_ids:
                            ServiceRegisterItemKey.objects.create(
                                serviceregisteritem=ritem,
                                serviceregisterattroption_id=opt)
                    else:
                        # 修改价格维度属性不变
                        ritem = ServiceRegisterItem.objects.filter(id=item_id)
                        saved_items.append(ritem.first())
                        ritem.update(**item)
            else:
                for item in items:
                    item_id = item.pop('id', None)
                    name = item.pop('project_name')
                    if item_id is None:
                        opt = AttrOptions.objects.create(
                            tag_attr_id=settings.DEFAULT_TAG_ATTR_ID,
                            name=name, is_online=True)
                        item['service_register'] = register
                        item['key'] = str(opt.id)
                        ritem = ServiceRegisterItem.objects.create(**item)
                        saved_items.append(ritem)
                        ServiceRegisterItemKey.objects.create(
                            serviceregisteritem=ritem,
                            serviceregisterattroption=opt)
                    else:
                        ritem = ServiceRegisterItem.objects.filter(id=item_id)
                        ritem.update(**item)
                        fitem = ritem.first()
                        saved_items.append(fitem)
                        # 非标准应该只有一个opt
                        itemkey = ServiceRegisterItemKey.objects.get(serviceregisteritem=fitem)
                        auditattroptions = AuditAttrOptions.objects.filter(serviceregisteritem=fitem, is_delete=False).first()
                        if auditattroptions:
                            auditattroptions.name = name
                            auditattroptions.save()
                        elif itemkey.serviceregisterattroption.name != name:
                            auditattroptions, _ = AuditAttrOptions.objects.get_or_create(
                                name=name,
                                serviceregisteritem=fitem,
                                is_delete=False)

            # 保留提交过来的数据，未提交的以软删算
            ServiceRegisterItem.objects.filter(service_register=register) \
                .exclude(id__in=[x.id for x in saved_items]) \
                .update(is_delete=True)
    video_url = data['video_url'] if data.get('video_url') else ''
    video_pic = data['video_pic'] if data.get('video_pic') else ''
    if video_url != '' or video_pic != '':
        if video_url != '':
            video_url = ServiceRegisterVideo.cleaned_video_url(video_url)
        if ServiceRegisterVideo.objects.filter(serviceregister_id=register.id).exists():
            video = ServiceRegisterVideo.objects.get(serviceregister_id=register.id)
            if video_url != video.get_url() or video_pic != video.video_pic:
                if video_url != video.get_url():
                    if video_url == '':
                        video.video_url = video_url
                        video.video_pic = video_pic
                        video.persistent_status = VIDEO_CODE_STATUS.NOSTART
                        video.water_url = ''
                        video.persistentId = ''
                        video.save()
                    else:
                        video.video_url = video_url
                        video.video_pic = video_pic
                        video.persistent_status = VIDEO_CODE_STATUS.NOSTART
                        video.water_url = ''
                        video.persistentId = ''
                        video.save()
                        set_water_mark_to_video_service.delay(video.id)
                else:
                    video.video_pic = video_pic
                    video.save()
        else:
            video = ServiceRegisterVideo()
            video.serviceregister_id = register.id
            video.video_url = video_url
            video.video_pic = video_pic
            video.save()
            set_water_mark_to_video_service.delay(video.id)
    else:
        if ServiceRegisterVideo.objects.filter(serviceregister_id=register.id).exists():
            ServiceRegisterVideo.objects.get(serviceregister_id=register.id).delete()

    if data.get('is_draft'):
        return None

    review_type = SERVICE_REVIEW_TYPE.ORDINARY
    if data['is_specialreview']:
        review_type = SERVICE_REVIEW_TYPE.SPECIAL
    return add_reviewrecord(register, applier.id, review_type=review_type, explanation=explanation)


@bind_context('doctor/service/skus', login_required=True)
def doctor_skus(ctx, doctor_id=None, service_id=None):
    """
        获取医生可售卖的sku
    """
    if doctor_id:
        doctor = Doctor.objects.get(pk=doctor_id)
    else:
        doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)
    sku_ids = doctor.get_can_sell_sku_ids(doctor_id=doctor.id, service_id=service_id)
    return {
        'skus': skus_for_coupon(sku_ids),
    }


@bind_context('doctor/service/all', login_required=True)
def doctor_all_services(ctx, is_store_classification=None, page=None, search=None):
    """
        获取医生 所有 可售美购
    """
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)
    merchant = doctor.merchant
    if is_store_classification:
        filter_fields = {'merchant_id': merchant.id}
        if search:
            try:
                filter_fields['id'] = int(search)
            except:
                filter_fields['name__contains'] = search

        services = Service.objects.filter(**filter_fields).order_by('-id')
        total = services.count()
        services = services[(int(page) - 1)*10:int(page)*10].values('id', 'name', 'is_online')
        return {
                'services': {'services': list(services), 'total': total},
            }
    services = Service.objects.filter(merchant_id=merchant.id, is_online=True).order_by('-id').values('id', 'name')
    return {
        'services': list(services),
    }


@bind_context('doctor/service/is_online', login_required=True)
def judge_is_onlie(ctx, service_ids=[]):
    """
        判断美购是否是该医生的 且 是否在线
        返回合法美购
    """
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)
    online_services = Service.objects.filter(doctor_id=doctor.id, id__in=service_ids, is_online=True).values('id',
                                                                                                             'name')
    return {
        'online_services': list(online_services),
    }

@bind_context('doctor/merchant_service/is_online', login_required=True)
def merchant_service_is_onlie(ctx, service_ids=[]):
    """
        判断美购是否是该医生所属机构的 且 是否在线
        返回合法美购
    """
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)
    merchant = doctor.merchant
    online_services = Service.objects.filter(merchant_id=merchant.id, id__in=service_ids, is_online=True).values('id',
                                                                                                             'name')
    return {
        'online_services': list(online_services),
    }


@bind_context('doctor/service/can_use')
def doctor_service_can_use(ctx):
    """
    获取医生 可管理的所有可售美购
    如果是机构管理者，则为该机构下所有受该机构管理的医生的上线美购
    如果是普通医生，则为该医生的所有上线美购
    :param ctx:
    :return:
    """
    doctor = get_doctor_from_context(ctx)
    doctors = []
    doctors.append(doctor)
    if doctor.doctor_type == DOCTOR_TYPE.OFFICER:
        for item in Doctor.objects.filter(hospital=doctor.hospital, allow_hospital_agent=True):
            doctors.append(item)
    services = Service.objects.filter(doctor__in=doctors, is_online=True).order_by('-id').values('id', 'name')
    return {
        'services': list(services),
    }


@bind_context('doctor/get_merchant/service')
def doctor_merchant_service(ctx):
    """
    获取商家可管理的美购列表
    :param ctx:
    :return:
    """
    doctor = get_doctor_from_context(ctx)
    doctors = doctor.get_merchant_doctors()
    doctor_ids = [item['doctor_id'] for item in doctors]
    services = Service.objects.filter(doctor_id__in=doctor_ids)
    return [{
                'id': item.id,
                'name': item.name
            }
            for item in services]


@bind_context('doctor/service/info')
def doctor_service_info(ctx, service_id):
    """
    根据美购id获取美购信息
    :param service_id:
    :return:
    """
    service = Service.objects.get(id=service_id)
    return {
        'service_name': service.name,
        'is_online': service.is_online,
        'doctor_name': service.doctor.name if service.doctor else ''
    }


@bind_context('doctor/service_list/info')
def doctor_service_info(ctx, service_ids):
    """
    根据美购id list获取美购信息
    :param service_ids: list
    :return: list
    """
    services = Service.objects.filter(id__in=service_ids)
    service_info_list = []
    service_info_map = {}
    for service in services:
        service_info_map[service.id] = service
    for service_id in service_ids:
        service_info = service_info_map.get(service_id)
        if service_info:
            service_info_list.append({
                'id': service_id,
                'service_name': service_info.name,
                'doctor_name': service_info.doctor.name if service_info.doctor else '',
            })
    return service_info_list
