#!/usr/bin/env python
# coding=utf-8
import datetime
import json
import math

from api.models import Service, Shopcart, ServiceRegister, Q, Sum
from hippo.utils import merchant_doctors
from talos.models.diary import Diary
from talos.models.topic import Problem
from api.tool.datetime_tool import get_timestamp
from hippo.models import TrafficStatByHour

from rpc.tool.error_code import CODES, gen
from rpc.decorators import bind_context, list_interface

from gm_types.gaia import DIARY_CONTENT_LEVEL, SERVICE_REVIEW_STATUS as REVIEW
from gm_types.ascle.types import TRFFIC_CHART, CHAIN_CHART

from hippo.tool.user_tool import get_doctor_from_context
from hippo.tool.stats_tool import get_shopcart_amount
from hippo.models import SaleDetail, WorkReport, TrafficStat
from hippo.models.chain_hospital import MasterMerchant
from hippo.models.doctor import Doctor


@bind_context('doctor/stats/sale_detail', login_required=True)
@list_interface(offset_name='start_num', limit_name='count')
def sale_detail(ctx, month, count=10, start_num=0):
    """
        美购销售详情 since 2.0.0, 1.9.1已经有这个功能，但是统计方式改变了
        month: 按照月份统计，例2016-03
    """
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)

    DATE_FMT = '%Y-%m'
    month_date = datetime.datetime.strptime(month, DATE_FMT)

    sale_detail = SaleDetail.objects.filter(doctor=doctor, date=month_date).first()
    if not sale_detail:
        return gen(CODES.STATS_NOT_FOUND)

    result = {
        'order_total': {
            'real_order_amount': sale_detail.order_total,
            'used_total': sale_detail.validated_total,
            'refunded_total': sale_detail.refund_total,
        },
        'services': [],
    }

    service_infos = []
    if sale_detail.service_infos:
        service_infos = json.loads(sale_detail.service_infos)
    for item in service_infos[start_num: start_num + count]:
        service = Service.objects.get(id=item.get('id'))
        result['services'].append({
            'service_name': service.name,
            'real_order_amount': item.get('order_total', 0),
            'used_total': item.get('validated_total', 0),
            'refunded_total': item.get('refund_total', 0),
        })
    return result


@bind_context('doctor/stats/work_report', login_required=True)
def work_report(ctx, date=None):
    """
        工作日报，since 2.0.0
        date: 按天统计，例2016-03-17
    """
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)

    report = WorkReport.objects.filter(doctor=doctor).order_by('-date').first()
    if not report:
        return gen(CODES.STATS_NOT_FOUND)

    return report.to_data()


@bind_context('doctor/stats/real_traffic', login_required=True)
def real_traffic_data(ctx, doctor_id=None):
    """医生流量走向分析--实时统计"""

    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)

    doctor_ids = doctor.all_doctor_ids()
    if doctor_id and not doctor_id in doctor_ids:
        return gen(CODES.NO_PERMISSION)

    if doctor_id:
        doctor_ids = [doctor_id]

    online_service = Service.objects.filter(doctor__id__in=doctor_ids, is_online=True).count() #在线美购个数
    under_review_service = ServiceRegister.objects.filter(
        Q(doctor__id__in=doctor_ids) & (
                (Q(is_register=True) & Q(review_status=REVIEW.PASS)) | Q(review_status=REVIEW.UNDER_REVIEW)
    )).count()                                                                       #审核中美购个数
    active_diary = Diary.objects.filter(doctor_id__in=doctor_ids, topics__isnull=False).distinct().count() #日记个数
    active_good_diary = Diary.objects.filter(
        doctor_id__in=doctor_ids, content_level=DIARY_CONTENT_LEVEL.EXCELLENT, topics__isnull=False
    ).distinct().count()                                                            #优质日记个数
    topic = Problem.objects.filter(diary__doctor_id__in=doctor_ids).count()         #日记本个数
    shopcart_count = Shopcart.objects.filter(service__doctor__id__in=doctor_ids, service__is_online=True).count() #购物车sku个数
    shopcart_amount = sum(get_shopcart_amount(doctor_id) for doctor_id in doctor_ids)   #购物车sku总金额

    result = {
        'online_service': online_service, 
        'under_review_service': under_review_service, 
        'active_diary': active_diary,
        'active_good_diary': active_good_diary,
        'topic': topic, 
        'shopcart_count': shopcart_count, 
        'shopcart_amount': shopcart_amount 
    }

    return result


def growth_factor(num):
    """
        add at 2017-03-30
        !!! 若是调整务必考虑之前展示的兼容 !!!
    """
    return int(math.ceil(num * 2.1))


def gen_pv(service_pv_num, home_pv_num):
    return growth_factor(service_pv_num) + growth_factor(home_pv_num)


@bind_context('doctor/stats/day_traffic', login_required=True)
def traffic_data(ctx, doctor_ids, start_time, end_time, is_day=False, chart_type=None):
    """医生流量走向分析--按天统计
    start_time: 2000-01-01
    chart_type: 按天统计数据类型
    """
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)

    qs = TrafficStat.objects.filter(
        doctor_id__in=doctor_ids, date__gte=start_time, date__lte=end_time
    ).values('date').annotate(
        service_pv_num=Sum('service_pv_num'),
        home_pv_num=Sum('home_pv_num'),
        phone_received_num=Sum('phone_received_num'),
        phone_not_received_num=Sum('phone_not_received_num'),
        conversation_num=Sum('conversation_num'),
        created_order_num=Sum('created_order_num'),
        created_order_money=Sum('created_order_money'),
        paid_order_num=Sum('paid_order_num'),
        paid_order_money=Sum('paid_order_money'),
        validate_order_num=Sum('validate_order_num'),
        validate_order_money=Sum('validate_order_money'),
        new_diary_num=Sum('new_diary_num')
    ).order_by('date')

    # 固定统计数据, 数据库找出来Sum即可
    items = ['conversation_num', 'created_order_num', 'created_order_money',
             'paid_order_num', 'paid_order_money', 'validate_order_num', 'validate_order_money',
             'new_diary_num']
    data = {key: 0 for key in items}
    data['pv_num'] = 0
    data['phone_num'] = 0
    data['chart_days'] = []  # 不同tab查看不同的详细统计
    for stat in qs:
        # 页面浏览量
        pv_num = gen_pv(stat['service_pv_num'], stat['home_pv_num'])
        data['pv_num'] += pv_num
        # 电话数 = 接通 + 未接通
        phone_num = stat['phone_received_num'] + stat['phone_not_received_num']
        data['phone_num'] += phone_num
        for key in items:
            data[key] += stat.get(key, 0)
        if is_day:
            # 一天的统计，三维数组表示，三项分别是 时间戳、左边轴的值、右边轴的值
            oneday = [get_timestamp(datetime.datetime.strptime(stat['date'], '%Y-%m-%d')), 0, 0]
            if chart_type == TRFFIC_CHART.PV:
                oneday[1] = pv_num
            elif chart_type == TRFFIC_CHART.CONSULTING:
                oneday[1] = phone_num
                oneday[2] = stat['conversation_num']
            elif chart_type == TRFFIC_CHART.ORDER:
                oneday[1] = stat['created_order_num']
                oneday[2] = stat['created_order_money']
            elif chart_type == TRFFIC_CHART.PAY:
                oneday[1] = stat['paid_order_num']
                oneday[2] = stat['paid_order_money']
            elif chart_type == TRFFIC_CHART.VALIDATE:
                oneday[1] = stat['validate_order_num']
                oneday[2] = stat['validate_order_money']
            elif chart_type == TRFFIC_CHART.DIARY:
                oneday[1] = stat['new_diary_num']
            data['chart_days'].append(oneday)
    # 首页接口兼容，去除不必要字段
    if chart_type is None:
        data.pop('chart_days')
        data.pop('created_order_money')
        data.pop('paid_order_money')
        data.pop('validate_order_money')
        data.pop('new_diary_num')
    return data


@bind_context('doctor/stats/day_tracffic_by_hour')
def traffic_data_hour(ctx, start_time, end_time, chart_type=None):
    """
    页面浏览按小时统计
    :param chart_type:
    :param ctx:
    :param start_time:
    :param end_time:
    :return:
    """
    doctor = get_doctor_from_context(ctx)
    doctors = merchant_doctors(doctor.id)
    if doctors:
        doctor_ids = [doctor.id for doctor in doctors]
    else:
        doctor_ids = [doctor.id, ]
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)
    qs = TrafficStatByHour.objects.filter(
        doctor_id__in=doctor_ids, date__gte=start_time, date__lte=end_time
    )
    res = []
    if qs.count() > 0:
        if chart_type == TRFFIC_CHART.PV:
            service_pv_num = qs.values('hour').annotate(service_pv_num=Sum('service_pv_num'),
                                                        home_pv_num=Sum('home_pv_num')).order_by('hour')
            res.extend([
                           {
                               'y': gen_pv(item['service_pv_num'], item['home_pv_num']),
                               'z': 0
                           } for item in service_pv_num
                           ])

        elif chart_type == TRFFIC_CHART.CONSULTING:
            phone_received_num = qs.values('hour').annotate(
                phone_received_num=Sum('phone_received_num'),
                conversation_num=Sum('conversation_num'),
                phone_not_received_num=Sum('phone_not_received_num')
            ).order_by('hour')
            res.extend([
                           {
                               'y': item['phone_received_num'] + item['phone_not_received_num'],
                               'z': item['conversation_num']
                           } for item in phone_received_num
                           ])
        elif chart_type == TRFFIC_CHART.ORDER:
            created_order_num = qs.values('hour').annotate(
                created_order_num=Sum('created_order_num'),
                created_order_money=Sum('created_order_money')
            ).order_by('hour')
            res.extend(
                [{
                     'y': item['created_order_num'],
                     'z': item['created_order_money']
                 } for item in created_order_num]
            )

        elif chart_type == TRFFIC_CHART.PAY:
            paid_order_num = qs.values('hour').annotate(
                paid_order_num=Sum('paid_order_num'),
                paid_order_money=Sum('paid_order_money')
            ).order_by('hour')
            res.extend(
                [{
                     'y': item['paid_order_num'],
                     'z': item['paid_order_money']
                 } for item in paid_order_num]
            )
        elif chart_type == TRFFIC_CHART.VALIDATE:
            validate_order_num = qs.values('hour').annotate(
                validate_order_num=Sum('validate_order_num'),
                validate_order_money=Sum('validate_order_money')
            ).order_by('hour')
            res.extend(
                [{
                     'y': item['validate_order_num'],
                     'z': item['validate_order_money']
                 } for item in validate_order_num]
            )
        elif chart_type == TRFFIC_CHART.DIARY:
            new_diary_num = qs.values('hour').annotate(
                num=Sum('new_diary_num')).order_by('hour')
            res.extend(
                [{
                     'y': item['num'],
                     'z': 0
                 } for item in new_diary_num]
            )
    else:
        res.append({
            'y': 0,
            'z': 0
        })
    return {
        'chart_hours': res
    }


@bind_context('doctor/stats/chain_chart', login_required=True)
def chain_chart(ctx, doctor_ids, start_time, end_time, chart_type=None):
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)
    qs = TrafficStat.objects.filter(
        doctor_id__in=doctor_ids, date__gte=start_time, date__lte=end_time
    ).values('date').annotate(
        service_pv_num=Sum('service_pv_num'),
        home_pv_num=Sum('home_pv_num'),
        phone_received_num=Sum('phone_received_num'),
        phone_not_received_num=Sum('phone_not_received_num'),
        conversation_num=Sum('conversation_num'),
        created_order_num=Sum('created_order_num'),
        created_order_money=Sum('created_order_money'),
        paid_order_num=Sum('paid_order_num'),
        paid_order_money=Sum('paid_order_money'),
        validate_order_num=Sum('validate_order_num'),
        validate_order_money=Sum('validate_order_money'),
        new_diary_num=Sum('new_diary_num')
    ).order_by('date')
    result = list()
    for stat in qs:
        # 页面浏览量
        pv_num = gen_pv(stat['service_pv_num'], stat['home_pv_num'])
        # 电话数 = 接通 + 未接通
        phone_num = stat['phone_received_num'] + stat['phone_not_received_num']
        oneday = [get_timestamp(datetime.datetime.strptime(stat['date'], '%Y-%m-%d')), 0]
        if chart_type == CHAIN_CHART.PV:
            oneday[1] = pv_num
        elif chart_type == CHAIN_CHART.PHONE:
            oneday[1] = phone_num
        elif chart_type == CHAIN_CHART.MESSAGE:
            oneday[1] = stat['conversation_num']
        elif chart_type == CHAIN_CHART.ORDERNUM:
            oneday[1] = stat['created_order_num']
        elif chart_type == CHAIN_CHART.ORDERAMOUNT:
            oneday[1] = stat['created_order_money']
        elif chart_type == CHAIN_CHART.PAYNUM:
            oneday[1] = stat['paid_order_num']
        elif chart_type == CHAIN_CHART.PAYAMOUNT:
            oneday[1] = stat['paid_order_money']
        elif chart_type == CHAIN_CHART.VALIDATENUM:
            oneday[1] = stat['validate_order_num']
        elif chart_type == CHAIN_CHART.VALIDATEAMOUNT:
            oneday[1] = stat['validate_order_money']
        elif chart_type == CHAIN_CHART.DIARY:
            oneday[1] = stat['new_diary_num']
        result.append(oneday)
    return result


@bind_context('doctor/stats/chain_table', login_required=True)
def chain_table(ctx, doctor_ids, start_time, end_time):
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)
    qs = TrafficStat.objects.filter(
        doctor_id__in=doctor_ids, date__gte=start_time, date__lte=end_time
    ).values('date').annotate(
        service_pv_num=Sum('service_pv_num'),
        home_pv_num=Sum('home_pv_num'),
        phone_received_num=Sum('phone_received_num'),
        phone_not_received_num=Sum('phone_not_received_num'),
        conversation_num=Sum('conversation_num'),
        created_order_num=Sum('created_order_num'),
        created_order_money=Sum('created_order_money'),
        paid_order_num=Sum('paid_order_num'),
        paid_order_money=Sum('paid_order_money'),
        validate_order_num=Sum('validate_order_num'),
        validate_order_money=Sum('validate_order_money'),
        new_diary_num=Sum('new_diary_num')
    ).order_by('date')
    # 固定统计数据, 数据库找出来Sum即可
    items = ['conversation_num', 'created_order_num', 'created_order_money',
             'paid_order_num', 'paid_order_money', 'validate_order_num', 'validate_order_money',
             'new_diary_num']
    data = {key: 0 for key in items}
    data['pv_num'] = 0
    data['phone_num'] = 0
    data['chart_days'] = []  # 不同tab查看不同的详细统计
    for stat in qs:
        # 页面浏览量
        pv_num = gen_pv(stat['service_pv_num'], stat['home_pv_num'])
        data['pv_num'] += pv_num
        # 电话数 = 接通 + 未接通
        phone_num = stat['phone_received_num'] + stat['phone_not_received_num']
        data['phone_num'] += phone_num
        for key in items:
            data[key] += stat.get(key, 0)
    return data


@bind_context('doctor/stats/chain_list', login_required=True)
def chain_table(ctx):
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        return gen(CODES.DOCTOR_NOT_FOUND)
    mastermerchant = MasterMerchant.objects.filter(
        mastermerchant_id=doctor.d_merchant.id, is_operetor_related=True).first()
    if mastermerchant:
        doctor_ids = mastermerchant.slavemerchants.values_list('slavemerchant__doctor_id', flat=True)
        doctors = Doctor.objects.filter(id__in=doctor_ids) | Doctor.objects.filter(id=doctor.id)
    else:
        doctors = Doctor.objects.filter(id=doctor.id)
    return [{
        'id': d.id,
        'name': d.name
    } for d in doctors]
