# -*- coding: UTF-8 -*-
import math
import json
from datetime import datetime
from django.db import IntegrityError
from django.db.models import Q, Min
from api.models import Service, ItemWiki, ServiceItemWiki, ServiceTag, Tag, ServiceReserve, ServiceItem
from api.models import LockList, ServiceLock, SKULock, SkuExamineList, SKUExamine, ServiceRegister, ServiceItemKey
from rpc.decorators import bind_context, bind
from rpc.exceptions import (RPCIntegrityError, RPCNotFoundException)
from rpc.tool.dict_mixin import to_dict
from rpc.tool.log_tool import info_logger
from ..datatables import ServiceDT
from ..models import UserPerm
from ..queries.service import ServiceDQ
from ..queries.locklist import LockListDQ, SKULockListDQ, SKUUnlockDQ
from ..utils import check_business, check_operate, operate_business, get_business_team
from hera.queries.choice_query import choice_query
from api.tool.service_tool import ServiceConfig
from gm_types.gaia import OPERTOR_REVIEW_TYPE

from hera.views.serviceregister import get_serviceregister_detail, get_service_detail

uri_pre = 'hera/service'


@bind_context(uri_pre + '/choices')
def service_choices(ctx, q='', page=1, num=30, initial=None, singleattr=False, seckill=False, stock=False,
                    is_online=False, is_lock=False, special=None):
    page = int(page)
    num = int(num)

    query = choice_query(Service, ['id', 'name'], 'id', q, initial)

    qry = Q()
    if singleattr:
        qry &= Q(is_multiattribute=False)
    if seckill:
        qry &= ~Q(gengmei_price=0)
    if is_online:
        qry &= Q(is_online=True)
    if special is not None:
        qry &= Q(specialitem__special_id=special)

    query = query.filter(qry)
    # total_count = query.count()
    total_count = 0
    start_pos = (page - 1) * num
    start_pos = start_pos if start_pos >= 0 else 0
    results = [
        {
            'id': obj.id,
            'text': u'{}:{}({}){}{}'.format(
                obj.id, obj.name,
                u'在线' if obj.is_online else u'下线',
                u'(已锁定)' if is_lock and obj.is_lock else u'',
                u' 库存: %d' % obj.real_stock if stock and obj.real_stock else '',
            ),  # 库存为负数
        } for obj in query[start_pos: start_pos + num]]
    return {'total_count': total_count, 'results': results, 'page': page, 'num': num}


@bind_context(uri_pre + '/serviceitem/choices')
def serviceitem_choices(ctx, q="", page=1, num=30, initial=None):
    """
    serviceitem 搜索
    :param ctx:
    :param q:
    :param page:
    :param num:
    :param initial:
    :return:
    """
    page = int(page)
    num = int(num)

    if initial is not None:
        if isinstance(initial, (list, tuple)):
            qry = Q(serviceitem_id__in=initial)
        else:
            qry = Q(serviceitem_id=initial)
    else:
        qry = Q(serviceitem_id__contains=q) | Q(serviceattroption__name__contains=q)

    query = ServiceItemKey.objects.filter(qry).order_by('-id')
    total_count = query.count()
    start_pos = (page - 1) * num
    start_pos = start_pos if start_pos >= 0 else 0

    results = [
            {
            'id': obj.serviceitem_id,
            'text': u'{}:{}'.format(
                obj.serviceitem_id, obj.serviceattroption.name),
            } for obj in query[start_pos: start_pos + num]
    ]
    return {'total_count': total_count, 'results': results, 'page': page, 'num': num}


@bind_context(uri_pre + '/query')
def service_query(ctx, options):
    if check_business(ctx.session.groups):
        # 判断是商务并且非商务leader
        user = ctx.session.user
        members = UserPerm.members(user)
        init_q = Q(doctor__business_partener__in=members)
    elif check_operate(ctx.session.user_id):
        business_ids = operate_business(ctx.session.user_id)
        init_q = Q(doctor__business_partener__id__in=business_ids)
    else:
        init_q = None
    dqobj = ServiceDQ(init_q=init_q)
    return dqobj.process(**options)


@bind_context(uri_pre + '/datatable')
def service_datatable(ctx, req_data):
    init_q = None
    _in, businessman_list, team_groups = get_business_team(ctx)
    if _in:
        init_q = Q(doctor__business_partener__in=businessman_list) | Q(doctor__business_group__in=team_groups)

    dtobj = ServiceDT(Service, init_q=init_q)
    return dtobj.process(req_data,
                         ['servicereg__id', 'name', 'doctor__name',
                          'doctor__hospital__name', 'doctor__business_partener__username'])


@bind_context(uri_pre + '/get')
def service_detail(ctx, service_id, options=None):
    """get service detail by service_id

    :param service_id: [integer]specify a service.
    :param options: [None|dict]specify fileds to return.
                    keys refer `rpc.tool.dict_mixin`
                        'fields':
                        'excludes':
                        'expands':
    """
    try:
        service = Service.objects.get(id=service_id)
    except:
        raise RPCNotFoundException
    if options is None:
        options = {
            'fields': None,
            'excludes': None,
            'expands': None,
        }
    service_data = to_dict(service, **options)
    service_data['itemwiki'] = list(
        ServiceItemWiki.objects.filter(service_id=service.id).values_list('itemwiki_id', flat=True))
    service_data['order_amount'] = service.real_order_amount
    service_data['stock'] = service.sell_num_limit
    service_data['is_floor_price'] = u'是' if service.is_floor_price else u'否'
    service_data['diaries_count'] = service.diaries_count
    service_data['business_partener_id'] = getattr(service.doctor.business_partener, 'id', None)
    service_data['business_partener_name'] = getattr(service.doctor.business_partener, 'username', u'无')
    return service_data


@bind_context(uri_pre + '/edit')
def service_edit(ctx, service_id=None, service_info=None):
    """create or modify service info
    """
    if service_info is None:
        return None
    itemwikies = service_info.pop('itemwiki', [])
    tags = service_info.pop('tags', [])
    service_info['doctor_id'] = service_info.pop('doctor')
    service_info['hospital_id'] = service_info.pop('hospital')
    service_info['wiki_id'] = service_info.pop('wiki')
    service_info.pop('is_floor_price')
    if service_id is None:
        try:
            service_info['sell_num_limit'] = service_info['total_num']
            service = Service.objects.create(**service_info)
        except IntegrityError:
            info_logger.info(__import__('traceback').format_exc())
            raise RPCIntegrityError
    else:
        sfilter = Service.objects.filter(id=service_id)
        if sfilter.count() != 1:
            raise RPCNotFoundException
        if sfilter[0].sell_num_limit <= 0 and (service_info['total_num'] - sfilter[0].real_sell_amount) > 0:
            service_info['sellcount_changetime'] = datetime.now()
        elif sfilter[0].sell_num_limit > 0 and (service_info['total_num'] - sfilter[0].real_sell_amount) <= 0:
            service_info['sellcount_changetime'] = datetime.now()
        sfilter.update(**service_info)
        service = sfilter[0]
    # 设置美购的状态变化时间

    service.sell_num_limit = service.real_stock
    service.save()  # TODO for data sync workaround
    service.smart_self_support()

    if itemwikies:
        new_itemwiki = set(ItemWiki.objects.filter(id__in=itemwikies))
        old_itemwiki = set([si.itemwiki for si in ServiceItemWiki.objects.filter(service_id=service.id)])
        for iw_obj in (new_itemwiki - old_itemwiki):
            ServiceItemWiki.objects.get_or_create(
                service_id=service.id,
                itemwiki=iw_obj)
        ServiceItemWiki.objects.filter(service_id=service.id,
                                       itemwiki__in=(old_itemwiki - new_itemwiki)).delete()
    if tags:
        new_tags = set(Tag.objects.filter(id__in=tags))
        old_tags = set(service.tags.all())
        for tag_obj in (new_tags - old_tags):
            ServiceTag.objects.get_or_create(
                service_id=service.id,
                tag=tag_obj)
        ServiceTag.objects.filter(
            service_id=service.id,
            tag__in=(old_tags - new_tags),
        ).delete()
    reservenum = ServiceReserve.objects.filter(service_id=service.id).count()
    data = {
        'reservenum': reservenum,
        'service_id': service.id,
        'sell_num_limit': service.sell_num_limit,
    }
    return data


@bind_context(uri_pre + '/batchset_service_field')
def service_batchset(ctx, service_ids, set_val, rel_field):
    # 批量设置多属性相关字段
    # 获取多属性美购
    info = {rel_field: set_val}
    # services_multiattr = Service.objects.filter(
    #        id__in=service_ids, is_multiattribute=True)
    # 获取非多属性美购
    services_nonmulti = Service.objects.filter(
        id__in=service_ids, is_multiattribute=False)
    services_nonmulti.update(**info)
    # for service in services_multiattr:
    #    service.items.update(**info)
    return True


@bind_context(uri_pre + '/get_from_ids_seckill')
def get_from_ids_seckill(ctx, ids):
    """
    根据美购ID获取秒杀专题的serviceitem信息
    :param ids: 美购itemid列表(秒杀专题)
    create by oldman 2017-01-08
    """
    services_data = []
    serviceitems = ServiceItem.objects.filter(parent_id=0, service_id__in=ids, is_delete=False).order_by('service_id')
    for serviceitem in serviceitems:
        price_info = serviceitem.get_default_price_info()
        data = {
            'apply_id': u'',
            'is_apply': False,
            'serviceitem_id': serviceitem.id,
            'service_id': serviceitem.service.id,
            'service_name': serviceitem.service.name,
            'project_name': ''.join(serviceitem.items_name),
            'rank': 0,
            'gengmei_price': price_info.get('gengmei_price', 0),
            'active_price': price_info.get('gengmei_price', 0),
            'pre_payment_price': price_info.get('pre_payment_price', 0),  # 设置为秒杀价的默认值
            'add_stock': 0,
            'tip': u'',
            'discount': price_info.get('discount', 0),  # 抽成设置为秒杀价的百分之十,向上取整
            'sell_num_limit': 20,
        }

        services_data.append(data)
    return services_data


@bind_context(uri_pre + '/get_from_serviceitem_ids_seckill')
def get_from_serviceitem_ids(ctx, serviceitem_ids):
    """
    专场根据skuID获取serviceitem信息
    """
    services_data = []
    for serviceitem_id in serviceitem_ids:
        serviceitem = ServiceItem.objects.get(id=serviceitem_id)
        price_info = serviceitem.get_default_price_info()
        data = {
            'apply_id': '',
            'item_id': serviceitem.id,
            'service_id': serviceitem.service.id,
            'serviceitem_id': serviceitem.id,
            'service_name': serviceitem.service.name,
            'project_name': ''.join(serviceitem.items_name),
            'gengmei_price': price_info.get('gengmei_price', 0),
            'active_price': price_info.get('gengmei_price', 0),
            'pre_payment_price': price_info.get('pre_payment_price', 0),
            'discount': price_info.get('discount', 0),
            'sell_num_limit': 20,
            'sell_num': 0,
            'rank': 0,
            'tip': u'',
            'add_stock': 0,
        }
        services_data.append(data)
    return services_data


@bind_context(uri_pre + '/listupdate')
def service_listupdate(ctx, items):
    info = []
    for obj in items:
        service = Service.objects.get(pk=obj['key'])
        service.is_online = obj['is_online']
        service.ordering = obj['ordering']
        service.smart_self_support()
        service.save()
        info.append(obj['key'])
    return info


@bind_context(uri_pre + '/timeupdate')
def service_timeupdate(ctx, items):
    info = []
    for obj in items:
        try:
            service = Service.objects.get(pk=obj['key'])
            datetime.strptime(obj['start_time'], "%Y-%m-%d %H:%M:%S")
            service.start_time = obj['start_time']
            service.save()
        except ValueError:
            pass
        info.append(obj['key'])
    return info


@bind_context(uri_pre + '/lock_list/query')
def lock_list_query(ctx, options):
    dqobj = LockListDQ()
    return dqobj.process(**options)


@bind_context(uri_pre + '/lock_list/get')
def lock_list_query(ctx, id):
    try:
        locklist = LockList.objects.get(id=id)
    except:
        raise RPCNotFoundException
    locklist_data = to_dict(locklist)
    locklist_data['lock_services'] = [
        {
            'id': service.id,
            'name': service.name,
            'doctor': service.doctor.name,
            'hospital': service.doctor.hospital.name,
            'bussiness_partner': getattr(service.doctor.business_partener, 'username', u''),
        } for service in locklist.services.all()
        ]
    return locklist_data


@bind_context(uri_pre + '/lock_list/edit')
def lock_list_query(ctx, id, lock_info):
    if lock_info is None:
        return None
    lockservices_id = lock_info.pop('lockservice_id')
    if id is None:
        try:
            locklist = LockList.objects.create(**lock_info)
        except IntegrityError:
            raise RPCIntegrityError
    else:
        try:
            locklist = LockList.objects.get(id=id)
            for k, v in lock_info.iteritems():
                setattr(locklist, k, v)
            locklist.save()
        except:
            info_logger.info(__import__('traceback').format_exc())
            raise RPCNotFoundException

    new_services = set(Service.objects.filter(id__in=lockservices_id))
    old_services = set(locklist.services.all())
    for service in (new_services - old_services):
        ServiceLock.objects.get_or_create(
            locklist_id=locklist.id,
            service=service)
    ServiceLock.objects.filter(
        locklist_id=locklist.id,
        service__in=(old_services - new_services),
    ).delete()
    return locklist.id


@bind_context(uri_pre + '/lock_list/get_service')
def lock_get_services(ctx, services_ids):
    services = Service.objects.filter(id__in=services_ids, is_online=True)
    services_date = [
        {
            'id': service.id,
            'name': service.name,
            'doctor': service.doctor.name,
            'hospital': service.doctor.hospital.name,
            'bussiness_partner': getattr(service.doctor.business_partener, 'username', u''),
        } for service in services
        ]
    return services_date


@bind_context(uri_pre + '/set_insurance')
def set_insurance(ctx, source_insurance_id, target_insurance_id, tags):
    tags = filter(lambda x: x != '', tags)
    services = Service.objects.filter(
        tags__id__in=tags,
        is_online=True,
        insurance=source_insurance_id,
    )
    services.update(insurance=target_insurance_id, user_safe=False)
    return Service.objects.filter(insurance=target_insurance_id).count()


@bind(uri_pre + '/set_config')
def service_config(config):
    ServiceConfig.set(config)


@bind_context(uri_pre + '/get_config')
def get_service_config(ctx):
    return ServiceConfig.get()


@bind_context(uri_pre + '/skulock_list/query')
def skulock_list_query(ctx, options):
    dqobj = SKULockListDQ()
    return dqobj.process(**options)


@bind_context(uri_pre + '/skulock_list/get')
def skulock_list_query(ctx, id):
    try:
        locklist = LockList.objects.get(id=id)
    except:
        raise RPCNotFoundException
    locklist_data = to_dict(locklist)
    locklist_data['lock_skus'] = [
        {
            'id': sku.id,
            'name': sku.service.name,
            'doctor': sku.service.doctor.name,
            'hospital': sku.service.doctor.hospital.name,
            'bussiness_partner': getattr(sku.service.doctor.business_partener, 'username', u''),
        } for sku in locklist.skus.all()
        ]
    return locklist_data


@bind_context(uri_pre + '/skulock_list/edit')
def skulock_list_query(ctx, id, lock_info):
    if lock_info is None:
        return None
    lockskus_id = lock_info.pop('locksku_id')
    if id is None:
        try:
            locklist = LockList.objects.create(**lock_info)
        except IntegrityError:
            raise RPCIntegrityError
    else:
        try:
            locklist = LockList.objects.get(id=id)
            for k, v in lock_info.iteritems():
                setattr(locklist, k, v)
            locklist.save()
        except:
            info_logger.info(__import__('traceback').format_exc())
            raise RPCNotFoundException

    new_skus = set(ServiceItem.objects.filter(parent_id=0, id__in=lockskus_id))
    old_skus = set(locklist.skus.all())
    for sku in (new_skus - old_skus):
        SKULock.objects.get_or_create(
            locklist_id=locklist.id,
            serviceitem=sku)
    SKULock.objects.filter(
        locklist_id=locklist.id,
        serviceitem__in=(old_skus - new_skus),
    ).delete()
    return locklist.id


@bind_context(uri_pre + '/skulock_list/get_sku')
def skulock_get_skus(ctx, sku_ids):
    skus = ServiceItem.objects.filter(parent_id=0, id__in=sku_ids, service__is_online=True, is_delete=False)
    sku_data = [
        {
            'id': sku.id,
            'name': sku.service.name,
            'doctor': sku.service.doctor.name,
            'hospital': sku.service.doctor.hospital.name,
            'bussiness_partner': getattr(sku.service.doctor.business_partener, 'username', u''),
        } for sku in skus
        ]
    return sku_data


@bind_context(uri_pre + '/skuunlock_list/query')
def skulock_list_query(ctx, options):
    dqobj = SKUUnlockDQ()
    return dqobj.process(**options)


@bind_context(uri_pre + '/skuunlock_list/unlock')
def sku_unlock(ctx, ids):
    SKULock.objects.filter(id__in=ids).delete()
    return {'message': u'解锁成功！'}


@bind(uri_pre + '/get_byid')
def detail_for_artemis(service_id):
    data = {}
    try:
        service = Service.objects.get(id=service_id)
        data = {
            'id': service.id,
            'name': service.name,
        }
    except:
        pass
    return data


@bind_context(uri_pre + '/checksku_list/get')
def skulock_list_query(ctx, id):
    try:
        skuchecklist = SkuExamineList.objects.get(id=id)
    except:
        raise RPCNotFoundException
    skuchecklist_data = to_dict(skuchecklist)
    skuchecklist_data['check_skus'] = [
        {
            'id': sku.id,
            'name': sku.service.name,
            'doctor': sku.service.doctor.name,
            'hospital': sku.service.doctor.hospital.name,
            'bussiness_partner': getattr(sku.service.doctor.business_partener, 'username', u''),
        } for sku in skuchecklist.skus.all()
        ]
    return skuchecklist_data


@bind_context(uri_pre + '/checksku_list/edit')
def skulock_list_query(ctx, id, checksku_info):
    if checksku_info is None:
        return None
    checksku_id = checksku_info.pop('checksku_id')
    if id is None:
        try:
            skuchecklist = SkuExamineList.objects.create(**checksku_info)
        except IntegrityError:
            raise RPCIntegrityError
    else:
        try:
            skuchecklist = SkuExamineList.objects.get(id=id)
            for k, v in checksku_info.iteritems():
                setattr(skuchecklist, k, v)
            skuchecklist.save()
        except:
            info_logger.info(__import__('traceback').format_exc())
            raise RPCNotFoundException

    new_skus = set(ServiceItem.objects.filter(parent_id=0, id__in=checksku_id))
    old_skus = set(skuchecklist.skus.all())
    for sku in (new_skus - old_skus):
        SKUExamine.objects.get_or_create(
            skuexaminelist_id=skuchecklist.id,
            serviceitem=sku)
    SKUExamine.objects.filter(
        skuexaminelist_id=skuchecklist.id,
        serviceitem__in=(old_skus - new_skus),
    ).delete()
    return skuchecklist.id
