# coding=utf-8
# create by oldman at 2018/4/17
import datetime
import pdb

import math
from celery import shared_task
from django.conf import settings
from django.db.models import Count
from django.db.models import Sum, Min
from gm_types.doctor import DATE_TYPE

from api.models import BuDan
from api.models import Conversation, ConversationUserStatus
from api.models import MerchantStatDaily
from api.models import Message
from hippo.models import Doctor
from hippo.models import Merchant
from hippo.models import PhoneServiceRecord
from hippo.models.businessdata import ToHospital, BusinessData, Al_Merchant_Stat_Updates, MerchantStatDailyData
from rpc.context import get_rpc_remote_invoker
from rpc.tool.log_tool import logging_exception


def get_last_month_end(date_time):
    """
    获取给定时间上个月的lastday
    :param date_time:
    :return:
    """
    this_month_first = datetime.datetime(date_time.year, date_time.month, 1, 0, 0, 0)
    return (this_month_first - datetime.timedelta(days=1)).date()


def get_before_month_end(date_time, rank):
    """
    获取给定时间前rank月的月末的集合
    :param date_time:
    :param rank:
    :return:
    """
    res = []
    for i in range(0, rank):
        date_time = get_last_month_end(date_time)
        res.append(date_time)
    return res


@shared_task
def async_doctor_everyday_business_data():
    """
    统计每月截止到今天的仪表盘数据
    :return:
    """
    merchants = Merchant.objects.filter(is_online=True)
    rpc_invoker = get_rpc_remote_invoker()
    count = merchants.count()
    step = 1000
    begin = 0
    while begin < count:
        for merchant in merchants[begin: begin + step]:
            try:

                doctor_ids = [merchant_doctor.doctor.id for merchant_doctor in merchant.merchant_doctors.all()]
                now_time = datetime.datetime.today()
                end_time = datetime.datetime(now_time.year, now_time.month, now_time.day, 0, 0, 0)
                start_time = datetime.datetime(now_time.year, now_time.month, 1, 0, 0, 0)
                start_time_str = start_time.strftime('%Y-%m-%d %H:%M:%S')
                end_time_str = end_time.strftime('%Y-%m-%d %H:%M:%S')
                if now_time.day == 1:
                    diary_pv = 0
                    service_pv = 0
                    hospital_doctor_pv = 0
                else:
                    partition_date = (end_time - datetime.timedelta(days=1)).date()
                    try:
                        pv = get_pv(partition_date, merchant.id)
                    except Exception as e:
                        pv = None
                    diary_pv = pv.diary_pv if pv else 0
                    service_pv = pv.service_pv if pv else 0
                    hospital_doctor_pv = pv.home_pv if pv else 0

                diary_result = rpc_invoker['diary/count_by_doctor_ids'](doctor_ids=doctor_ids,
                                                                        start_time=start_time_str,
                                                                        end_time=end_time_str
                                                                        ).unwrap()
                # diary_result = {
                #     'total':10,
                #     'five_stars_num': 5,
                #     'four_stars_num': 5,
                # }
                advertise = rpc_invoker['artemis/account/doctors/cost'](doctor_ids=doctor_ids,
                                                                        start_time=start_time_str,
                                                                        end_time=end_time_str).unwrap()['costs']

                phone = get_phone(doctor_ids, start_time, end_time)
                message_count = get_effective_message(doctor_ids, start_time, end_time)
                message = message_count['num']
                connect_phone = get_phone(doctor_ids, start_time, end_time, status=2)
                effective_message = message_count['effect_num']
                to_the_hospital = get_to_hospital(doctor_ids, start_time, end_time)
                costs = get_costs(doctor_ids, start_time, end_time)
                consumption_people = costs['person_num']
                consumption_cost = costs['total']

                business = BusinessData.objects.get_or_create(merchant_id=merchant.id,
                                                              doctor_id=merchant.doctor.id,
                                                              time_type=DATE_TYPE.THIS_MONTH)[0]
                business.doctor_id = merchant.doctor_id
                business.new_diary = diary_result['total']
                business.five_stars_diary = diary_result['five_stars_num']
                business.four_stars_diary = diary_result['four_stars_num']
                business.advertise = advertise
                business.diary_pv = diary_pv
                business.service_pv = service_pv
                business.hospital_doctor_pv = hospital_doctor_pv
                business.phone = phone
                business.message = message
                business.connect_phone = connect_phone
                business.effective_message = effective_message
                business.to_the_hospital = to_the_hospital
                business.consumption_people = consumption_people
                business.consumption_cost = consumption_cost
                business.save()
                print business.id
            except Exception as e:
                logging_exception()
                print e.message
                continue
        begin += step

    # 日记本排序
    cities = set([merchant.doctor.hospital.city for merchant in merchants if merchant.doctor.hospital])
    for city in cities:
        businesses = BusinessData.objects.filter(doctor__hospital__city=city,
                                                 time_type=DATE_TYPE.THIS_MONTH).order_by('-new_diary')
        for index, data in enumerate(businesses):
            data.diary_rank = index + 1
            data.save()


@shared_task
def async_doctor_month_business_data():
    """
    统计三个月，六个月的仪表盘的信息
    :return:
    """
    # 统计三个月的
    merchants = Merchant.objects.filter(is_online=True)
    rpc_invoker = get_rpc_remote_invoker()
    count = merchants.count()
    step = 1000
    begin = 0
    print count
    while begin < count:
        for merchant in merchants[begin: begin + step]:
            try:
                print merchant.id
                doctor_ids = [merchant_doctor.doctor.id for merchant_doctor in merchant.merchant_doctors.all()]
                now_time = datetime.datetime.today()
                end_time = datetime.datetime(now_time.year, now_time.month, 1, 0, 0, 0)
                middle_time_three = end_time - datetime.timedelta(days=70)
                star_time_three_month = datetime.datetime(middle_time_three.year, middle_time_three.month, 1, 0, 0, 0)
                star_time_three_month_str = star_time_three_month.strftime('%Y-%m-%d %H:%M:%S')
                end_time_str = end_time.strftime('%Y-%m-%d %H:%M:%S')

                date_times_three = get_before_month_end(now_time, 3)
                pv = get_pv_by_time_zone(date_times_three, merchant.id)
                diary_pv = pv.get('diary_pv', 0) if pv else 0
                service_pv = pv.get('service_pv', 0) if pv else 0
                hospital_doctor_pv = pv.get('home_pv', 0) if pv else 0

                diary_result = rpc_invoker['diary/count_by_doctor_ids'](doctor_ids=doctor_ids,
                                                                        start_time=star_time_three_month_str,
                                                                        end_time=end_time_str
                                                                        ).unwrap()
                advertise = rpc_invoker['artemis/account/doctors/cost'](doctor_ids=doctor_ids,
                                                                        start_time=star_time_three_month_str,
                                                                        end_time=end_time_str).unwrap()['costs']
                phone = get_phone(doctor_ids, star_time_three_month, end_time)
                # message_count = get_effective_message(doctor_ids, star_time_three_month, end_time)
                # message = message_count['num']
                connect_phone = get_phone(doctor_ids, star_time_three_month, end_time, status=2)
                # effective_message = message_count['effect_num']
                to_the_hospital = get_to_hospital(doctor_ids, star_time_three_month, end_time)
                costs = get_costs(doctor_ids, star_time_three_month, end_time)
                consumption_people = costs['person_num']
                consumption_cost = costs['total']

                business = BusinessData.objects.get_or_create(merchant_id=merchant.id,
                                                              doctor_id=merchant.doctor.id,
                                                              time_type=DATE_TYPE.NEARLY_THERE_MONTH)[0]
                business.doctor_id = merchant.doctor_id
                business.new_diary = diary_result['total']
                business.five_stars_diary = diary_result['five_stars_num']
                business.four_stars_diary = diary_result['four_stars_num']
                business.advertise = advertise
                business.diary_pv = diary_pv
                business.service_pv = service_pv
                business.hospital_doctor_pv = hospital_doctor_pv
                business.phone = phone
                business.message = 0
                business.connect_phone = connect_phone
                business.effective_message = 0
                business.to_the_hospital = to_the_hospital
                business.consumption_people = consumption_people
                business.consumption_cost = consumption_cost
                business.save()
                print 1

            except Exception as e:
                print e.message
                logging_exception()
                continue
        begin += step
    # 日记本排序
    cities = set([merchant.doctor.hospital.city for merchant in merchants if merchant.doctor.hospital])
    for city in cities:
        businesses = BusinessData.objects.filter(doctor__hospital__city=city,
                                                 time_type=DATE_TYPE.NEARLY_THERE_MONTH).order_by('-new_diary')
        for index, data in enumerate(businesses):
            data.diary_rank = index + 1
            data.save()

    # 三个月的处理完毕
    # 统计六个月的
    count = merchants.count()
    step = 1000
    begin = 0
    while begin < count:
        for merchant in merchants[begin: begin + step]:
            try:

                doctor_ids = [merchant_doctor.doctor.id for merchant_doctor in merchant.merchant_doctors.all()]
                now_time = datetime.datetime.today()
                end_time = datetime.datetime(now_time.year, now_time.month, 1, 0, 0, 0)
                middle_time_six = end_time - datetime.timedelta(days=160)
                star_time_six_month = datetime.datetime(middle_time_six.year, middle_time_six.month, 1, 0, 0, 0)
                star_time_six_month_str = star_time_six_month.strftime('%Y-%m-%d %H:%M:%S')
                end_time_str = end_time.strftime('%Y-%m-%d %H:%M:%S')
                date_times_six = get_before_month_end(now_time, 6)
                pv = get_pv_by_time_zone(date_times_six, merchant.id)
                diary_pv = pv.get('diary_pv', 0) if pv else 0
                service_pv = pv.get('service_pv', 0) if pv else 0
                hospital_doctor_pv = pv.get('home_pv', 0) if pv else 0

                diary_result = rpc_invoker['diary/count_by_doctor_ids'](doctor_ids=doctor_ids,
                                                                        start_time=star_time_six_month_str,
                                                                        end_time=end_time_str
                                                                        ).unwrap()
                advertise = rpc_invoker['artemis/account/doctors/cost'](doctor_ids=doctor_ids,
                                                                        start_time=star_time_six_month_str,
                                                                        end_time=end_time_str).unwrap()['costs']

                phone = get_phone(doctor_ids, star_time_six_month, end_time)

                connect_phone = get_phone(doctor_ids, star_time_six_month, end_time, status=2)
                # effective_message = message_count['effect_num']
                to_the_hospital = get_to_hospital(doctor_ids, star_time_six_month, end_time)
                costs = get_costs(doctor_ids, star_time_six_month, end_time)
                consumption_people = costs['person_num']
                consumption_cost = costs['total']

                business = BusinessData.objects.get_or_create(merchant_id=merchant.id,
                                                              doctor_id=merchant.doctor.id,
                                                              time_type=DATE_TYPE.NEARLY_SIX_MONTH)[0]
                business.doctor_id = merchant.doctor_id
                business.new_diary = diary_result['total']
                business.five_stars_diary = diary_result['five_stars_num']
                business.four_stars_diary = diary_result['four_stars_num']
                business.advertise = advertise
                business.diary_pv = diary_pv
                business.service_pv = service_pv
                business.hospital_doctor_pv = hospital_doctor_pv
                business.phone = phone
                business.message = 0
                business.connect_phone = connect_phone
                business.effective_message = 0
                business.to_the_hospital = to_the_hospital
                business.consumption_people = consumption_people
                business.consumption_cost = consumption_cost
                business.save()

            except Exception as e:
                logging_exception()
                continue
        begin += step

    # 日记本排序
    cities = set([merchant.doctor.hospital.city for merchant in merchants if merchant.doctor.hospital])
    for city in cities:
        businesses = BusinessData.objects.filter(doctor__hospital__city=city,
                                                 time_type=DATE_TYPE.NEARLY_SIX_MONTH).order_by('-new_diary')
        for index, data in enumerate(businesses):
            data.diary_rank = index + 1
            data.save()

            # 六个月的处理完毕
    async_message_three()
    async_message_six()


def async_message_three():
    """
    同步私信
    :return:
    """
    businesses = BusinessData.objects.filter(time_type=DATE_TYPE.NEARLY_THERE_MONTH)
    count = businesses.count()
    step = 1000
    begin = 0
    now_time = datetime.datetime.today()
    end_time = datetime.datetime(now_time.year, now_time.month, 1, 0, 0, 0)
    middle_time_three = end_time - datetime.timedelta(days=70)
    while begin < count:
        for business in businesses[begin: begin + step]:
            try:
                print business.id
                doctor_ids = [merchant_doctor.doctor.id for merchant_doctor in business.merchant.merchant_doctors.all()]
                star_time_three_month = datetime.datetime(middle_time_three.year, middle_time_three.month, 1, 0, 0, 0)
                message_count = get_effective_message(doctor_ids, star_time_three_month, end_time)
                business.message = message_count['num']
                business.effective_message = message_count['effect_num']
                business.save()
            except:
                logging_exception()
                continue
        begin += step


def async_message_six():
    """
    同步私信
    :return:
    """
    businesses = BusinessData.objects.filter(time_type=DATE_TYPE.NEARLY_SIX_MONTH)
    count = businesses.count()
    step = 1000
    begin = 0
    now_time = datetime.datetime.today()
    end_time = datetime.datetime(now_time.year, now_time.month, 1, 0, 0, 0)
    middle_time_six = end_time - datetime.timedelta(days=160)
    star_time_six_month = datetime.datetime(middle_time_six.year, middle_time_six.month, 1, 0, 0, 0)
    while begin < count:
        for business in businesses[begin: begin + step]:
            try:
                print business.id
                doctor_ids = [merchant_doctor.doctor.id for merchant_doctor in business.merchant.merchant_doctors.all()]
                star_time_six_month = datetime.datetime(star_time_six_month.year, star_time_six_month.month, 1, 0, 0, 0)
                message_count = get_effective_message(doctor_ids, star_time_six_month, end_time)
                business.message = message_count['num']
                business.effective_message = message_count['effect_num']
                business.save()
            except:
                logging_exception()
                continue
        begin += step


def get_pv(partition_date, merchant_id):
    merchant_stat_updates = MerchantStatDailyData.objects.get(merchant_id=merchant_id,
                                                              date=partition_date
                                                              )
    return merchant_stat_updates


def get_pv_by_time_zone(date_times, merchant_id):
    """

    :param date_times:
    :param merchant_id:
    :return:
    """
    try:
        res_data = MerchantStatDailyData.objects.filter(merchant_id=merchant_id, date__in=date_times
                                                        ).aggregate(diary_pv=Sum('diary_pv'),
                                                                    home_pv=Sum('home_pv'),
                                                                    service_pv=Sum('service_pv')
                                                                    )
        return res_data
    except:
        return None


def get_phone(doctor_ids, start_time, end_time, status=None):
    """
    获取400电话统计
    :param status: status == 2:接听成功
    :param doctor_ids: 医生ID list
    :param start_time: 统计开始时间
    :param end_time: 统计结束时间
    :return:
    """
    phones_querys = PhoneServiceRecord.objects.filter(doctor_id__in=doctor_ids).filter(call_time__gte=start_time,
                                                                                       call_time__lt=end_time)
    if status:
        phones_querys = phones_querys.filter(call_status=status)
    return phones_querys.count()


# def get_message(doctor_ids, start_time, end_time):
#     """
#     获取私信统计
#     :rtype: object
#     :param doctor_ids:
#     :param start_time:
#     :param end_time:
#     :return:
#     """
#     user_ids = list(Doctor.objects.filter(id__in=doctor_ids).values_list('user_id', flat=True))
#
#     messages = Message.objects.filter(send_time__gte=start_time, send_time__lt=end_time)
#     conversation_ids = list(ConversationUserStatus.objects.filter(
#         user_id__in=user_ids).values_list('conversation_id', flat=True))
#
#     useless_c_ids = Message.objects.filter(
#         send_time__gte=start_time, send_time__lt=end_time,
#         user_id__in=doctor_user_ids).values_list('conversation_id', flat=True)
#     messages = messages.filter(conversation_id__in=conversation_ids).exclude(
#         conversation_id__in=useless_c_ids)
#     conversations = set(messages.filter(conversation_id__in=conversation_ids).exclude(
#         conversation_id__in=useless_c_ids).values_list('conversation_id', flat=True))
#
#     num = 0
#     for conversation in conversations:
#         try:
#             message = messages.filter(conversation_id=conversation).first()
#             conversation = message.conversation
#             send_time = message.send_time
#             exsits_datetime_gt = message.send_time - datetime.timedelta(days=30)
#             exists_messages = Message.objects.filter(conversation=conversation,
#                                                      send_time__gte=exsits_datetime_gt,
#                                                      send_time__lt=send_time
#                                                      ).exists()
#             if not exists_messages:
#                 num += 1
#         except:
#             continue
#
#     return num


def get_effective_message(doctor_ids, start_time, end_time):
    """
    獲取私信，有效私信統計
    :param doctor_ids:
    :param start_time:
    :param end_time:
    :return:
    """
    doctor_user_ids = list(Doctor.objects.all().values_list('user_id', flat=True))
    user_ids = list(Doctor.objects.filter(id__in=doctor_ids).values_list('user_id', flat=True))
    messages = Message.objects.filter(send_time__gte=start_time, send_time__lt=end_time)
    conversation_ids = list(ConversationUserStatus.objects.filter(
        user_id__in=user_ids).values_list('conversation_id', flat=True))

    useless_c_ids = Message.objects.filter(
        send_time__gte=start_time, send_time__lt=end_time,
        user_id__in=doctor_user_ids).values_list('conversation_id', flat=True)
    messages = messages.filter(conversation_id__in=conversation_ids).exclude(
        conversation_id__in=useless_c_ids)
    conversations = set(messages.filter(conversation_id__in=conversation_ids).exclude(
        conversation_id__in=useless_c_ids).values_list('conversation_id', flat=True))

    num = 0
    effect_num = 0
    for conversation in conversations:
        try:
            message = messages.filter(conversation_id=conversation).first()
            conversation = message.conversation
            send_time = message.send_time
            two_nums_time = send_time + datetime.timedelta(days=1)
            exsits_datetime_gt = message.send_time - datetime.timedelta(days=30)
            exists_messages = Message.objects.filter(conversation=conversation,
                                                     send_time__gte=exsits_datetime_gt,
                                                     send_time__lt=send_time
                                                     ).exists()
            if not exists_messages:
                num += 1
                exists_messages_two_nums = Message.objects.filter(conversation=conversation,
                                                                  send_time__gte=send_time,
                                                                  send_time__lt=two_nums_time).exclude(
                    id=message.id)
                if exists_messages_two_nums.exists():
                    effect_num += 1
        except:
            continue
    print num
    print effect_num
    return {'num': num,
            'effect_num': effect_num,
            }


def get_to_hospital(doctor_ids, start_time, end_time):
    """
    到院人数
    :param doctor_ids:
    :param start_time:
    :param end_time:
    :return:
    """
    to_hospital = ToHospital.objects.filter(doctor_id__in=doctor_ids).filter(tohospital_time__gte=start_time,
                                                                             tohospital_time__lt=end_time)
    total = to_hospital.aggregate(total=Sum('num'))
    return total['total']


def get_costs(doctor_ids, start_time, end_time):
    """
    消费金額
    :param doctor_ids:
    :param start_time:
    :param end_time:
    :return:
    """
    budan = BuDan.objects.filter(
        doctor_id__in=doctor_ids).filter(create_time__gte=start_time, create_time__lt=end_time)
    total = budan.aggregate(total=Sum('extra_consume'))['total']
    person_num = budan.values('user_phone').annotate(Count('user_phone')).count()
    return {
        'total': total,
        'person_num': person_num
    }


@shared_task
def async_merchantstatdaily_pv_data():
    """
    同步数据从数据组表到整形表
    :return:
    """
    today_date = datetime.datetime.today().date()
    async_date = today_date - datetime.timedelta(days=1)
    merchantstats = MerchantStatDaily.objects.filter(date=async_date)
    count = merchantstats.count()
    step = 1000
    begin = 0
    rate = settings.PV_RATE
    while begin <= count:
        for merchantstat in merchantstats[begin: begin + step]:
            try:

                merchantstatdiarydata, _ = MerchantStatDailyData.objects.get_or_create(
                    date=async_date,
                    merchant_id=merchantstat.merchant_id,
                )
                print merchantstat.merchant_id
                merchantstatdiarydata.ad_recharge = merchantstat.ad_recharge
                merchantstatdiarydata.ad_consume = merchantstat.ad_consume
                merchantstatdiarydata.offline_amount = merchantstat.offline_amount
                merchantstatdiarydata.validated_price = merchantstat.validated_price
                merchantstatdiarydata.validated_discount = merchantstat.validated_discount
                merchantstatdiarydata.validated_price_user = merchantstat.validated_price_user
                merchantstatdiarydata.rate = rate
                merchantstatdiarydata.service_pv = int(math.ceil(merchantstat.service_pv * rate))
                merchantstatdiarydata.home_pv = int(math.ceil(merchantstat.home_pv * rate))
                merchantstatdiarydata.diary_pv = int(math.ceil(merchantstat.diary_pv * rate))
                merchantstatdiarydata.save()
            except Exception as e:
                print e.message
                print 1
                continue
        begin += step
        # next 同步仪表盘数据的pv信息
