# coding=utf-8

import datetime

import requests
from django.db.models import Count
from celery import shared_task

from gm_types.gaia import CHANNEL_CALLBACK_TYPE

from rpc.context import get_current_context_or_throw_exception
from statistic import const_strings
from statistic.models import DoctorView
from statistic.utils.mail_utils import (
    get_conversation_noreply_mail, get_conversation_noreply_mail_weekly,
)

from api.tool.log_tool import logging_exception
from api.models import (
    Conversation, ConversationUserStatus, Doctor, Message,
    CONVERSATION_STATUS, PRIVATE_STATUS, PROBLEM_FLAG_CHOICES,
)
from talos.models.topic import TopicReply

from rpc.cache import ViewRecord
from rpc.context import get_rpc_remote_invoker

from services.talos_service import topic_filter


def view_increase_amount(model_name, id_value, count, reverse=False):
    for _ in xrange(count):
        view_increase(model_name, id_value, reverse)


@shared_task
def view_increase(model_name, id_value, reverse=False):
    """

    :param model_name:
    :param id_value:
    :param reverse: 相反的，做减法
    :return:
    """
    view = ViewRecord(model_name)
    if reverse:
        view[id_value] = int(view[id_value] or '1') - 1
    else:
        view[id_value] = int(view[id_value] or '0') + 1

    return view[id_value]


@shared_task
def allocate_stat_doctor():
    """医生数据统计
    """
    doctors = Doctor.objects.filter(is_online=True)
    for doctor in doctors:
        try:
            stat_doctor(doctor=doctor, update_doctor_info=True)
        except:
            logging_exception()
            continue
    return doctors.count()


@shared_task
def stat_doctor(day=None, doctor=None, update_doctor_info=False):
    if not day:
        day = datetime.date.today()
    next_day = day + datetime.timedelta(days=1)
    if day and doctor and doctor.user:
        doctor_view, new = DoctorView.objects.get_or_create(stat_date=day, doctor=doctor)

        # 医生当天回复的话题的数量
        replies = TopicReply.objects.filter(doctor_id=doctor.id, reply_date__gte=day, reply_date__lt=next_day)
        normal_replies = replies.filter(problem__private_status=PRIVATE_STATUS.NORMAL)
        doctor_view.reply_num = normal_replies.aggregate(Count('problem', distinct=True)).get('problem__count', 0)

        # 私信部分统计
        new_conversations = Conversation.objects.filter(is_empty=False)
        new_conversations = new_conversations.filter(created_time__range=[day, next_day])
        new_conversations = new_conversations.filter(user=doctor.user)
        # 新增私信
        doctor_view.new_pm_num = new_conversations.count()
        # 私信用户相关
        # 收到新用户私信数(单个用户首次给他发信)
        cv_users = set([])
        cv_users_noreply = set([])
        for cv in new_conversations.order_by('id'):
            cv_user = cv.user.exclude(id=doctor.user.id).latest('id')
            if cv_user not in cv_users:
                cv_users.add(cv_user)
                max_datetime_as_noreply = cv.created_time + datetime.timedelta(1)  # 判断未回复的时间点是1天
                # 未回复新用户私信数(24小时内未回复)
                is_reply = Message.objects.filter(
                    conversation_id=cv.id,
                    user_id=doctor.user.id,
                    send_time__lte=max_datetime_as_noreply,
                ).exists()
                if not is_reply:
                    cv_users_noreply.add(cv_user)
        doctor_view.new_pm_user_num = len(cv_users)
        doctor_view.noreply_pm_user_num = len(cv_users_noreply)

        # 回复私信总数
        reply_messages = Message.objects.filter(send_time__range=[day, next_day])
        reply_messages = reply_messages.filter(user=doctor.user)
        reply_pm_num = reply_messages.aggregate(Count('conversation', distinct=True)).get('conversation__count', 0)
        doctor_view.reply_pm_num = reply_pm_num

        # 未回复私信总数
        no_reply_cus = ConversationUserStatus.objects.filter(user=doctor.user).filter(conversation__is_empty=False)
        no_reply_cus = no_reply_cus.filter(status=CONVERSATION_STATUS.NEW)
        doctor_view.no_reply_pm_num = no_reply_cus.count()

        # 案例数量
        share_amount = 0
        # 医生的美购的所有案例
        for service in doctor.services.all():
            and_filter = {
                'service_id': service.id,
                'flag': PROBLEM_FLAG_CHOICES.NORMAL,
                'is_online': True,
            }
            a = topic_filter(and_filter=and_filter, is_count=True)
            share_amount += a

        # 医生的项目的所有案例
        for i in doctor.doctoritem_set.all():
            and_filter = {
                'link_doctor_item_id': i.id,
                'flag': PROBLEM_FLAG_CHOICES.NORMAL,
                'is_online': True,
            }
            a = topic_filter(and_filter=and_filter, is_count=True)
            share_amount += a

        doctor_view.share_topic_num = share_amount

        doctor_view.save()

        # doctor 里面的统计字段已不再使用，先注释掉对doctor的处理
        # 正常运行一个月后可清除 -- by ZhongChengyang 20170323
        # if update_doctor_info:
        #     # 更新Doctor的数据
        #     doctor.view_num = doctor_view.view_num
        #     doctor.reply_num = doctor_view.reply_num
        #     doctor.new_pm_num = doctor_view.new_pm_num
        #     doctor.no_reply_pm_num = doctor_view.no_reply_pm_num
        #     doctor.share_topic_num = doctor_view.share_topic_num
        #     doctor.save()
        return u"{}: {}".format(day, doctor.name)


@shared_task
def allocate_stat_doctor_conversation():
    """医生昨日新增私信统计
    """
    doctors = Doctor.objects.filter(is_online=True)
    date = datetime.date.today() - datetime.timedelta(days=1)
    for doctor in doctors:
        try:
            stat_doctor_new_conversation(date, doctor)
        except:
            logging_exception()
            continue
    return doctors.count()


@shared_task
def stat_doctor_new_conversation(day=None, doctor=None):
    if not day:
        day = datetime.date.today()
    next_day = day + datetime.timedelta(days=1)
    if day and doctor and doctor.user:
        doctor_view, new = DoctorView.objects.get_or_create(stat_date=day, doctor=doctor)
        # 私信部分统计
        new_conversations = Conversation.objects.filter(is_empty=False)
        new_conversations = new_conversations.filter(created_time__range=[day, next_day])
        new_conversations = new_conversations.filter(user=doctor.user)
        # 私信用户相关
        # 收到新用户私信数(单个用户首次给他发信)
        cv_users = set([])
        cv_users_noreply = set([])
        for cv in new_conversations.order_by('id'):
            cv_user = cv.user.exclude(id=doctor.user.id).latest('id')
            if cv_user not in cv_users:
                cv_users.add(cv_user)
                # 判断未回复的时间点是1天
                max_datetime_as_noreply = cv.created_time + datetime.timedelta(1)
                # 未回复新用户私信数(24小时内未回复)
                is_reply = Message.objects.filter(
                    conversation_id=cv.id,
                    user_id=doctor.user.id,
                    send_time__lte=max_datetime_as_noreply,
                ).exists()
                if not is_reply:
                    cv_users_noreply.add(cv_user)
        doctor_view.new_pm_user_num = len(cv_users)
        doctor_view.noreply_pm_user_num = len(cv_users_noreply)
        doctor_view.save()


@shared_task
def send_conversation_stat_mail(date=None):
    if not date:
        date = datetime.date.today() - datetime.timedelta(days=1)
    mail = get_conversation_noreply_mail(date)
    mail.send()


@shared_task
def send_conversation_weekly_stat_mail(date=None):
    if not date:
        date = datetime.date.today() - datetime.timedelta(days=1)
    mail = get_conversation_noreply_mail_weekly(date)
    mail.send()


class _SyncSharedTask(object):
    def __init__(self, func):
        self.__func = func

    def __call__(self, *args, **kwargs):
        return self.__func(*args, **kwargs)

    def delay(self, *args, **kwargs):
        try:
            raise Exception('.delay for this function is deprecated!')
        except Exception:
            logging_exception()

        self.__func(*args, **kwargs)

@shared_task
def add_diary_pv(ids=None):
    if (ids is None) or (type(ids) is not list):
        return

    rpc_invoker = get_rpc_remote_invoker()
    for diary_id in ids:
        rpc_invoker['diary/view_increase'](id=diary_id).unwrap()

@shared_task
def add_problem_pv(ids=None):
    if (ids is None) or (type(ids) is not list):
        return
    rpc_invoker = get_rpc_remote_invoker()
    rpc_invoker['topic/addview_by_ids'](topic_ids=ids).unwrap()


@shared_task
def record_newly_increased_device(device_id, timestamp):
    """
    记录当日新增设备信息
    :param device_id:
    :param timestamp:
    :return:
    """
    rpc_invoker = get_rpc_remote_invoker()
    rpc_invoker['demeter/push/record_newly_increased_device'](
        device_id=device_id,
        timestamp=timestamp
    ).unwrap()


# @shared_task(name="statistic.tasks.diary_view_increase_num")
# def _task_diary_view_increase_num(ids=()):
#     for id in ids:
#         diary_pv_cache.incrby(id, 1)


# @_SyncSharedTask
# def diary_view_increase_num(ids=()):
#     ids = [i for i in ids if i]
#     if not ids:
#         return
#
#     try:
#         ctx = get_current_context_or_throw_exception()
#         ctx.logger.app(global__diary_view_increase_num={"ids": ids})
#     except:
#         logging_exception()
#
#     _task_diary_view_increase_num.delay(ids)
#
#
# @shared_task(name="statistic.tasks.topic_view_increase_num")
# def _task_topic_view_increase_num(ids=()):
#     for id in ids:
#         view = ViewRecord(const_strings.TOPIC_VIEW)
#         view[id] = int(view[id] or '0') + 1
#
#
# @_SyncSharedTask
# def topic_view_increase_num(ids=()):
#     ids = [i for i in ids if i]
#     if not ids:
#         return
#
#     try:
#         ctx = get_current_context_or_throw_exception()
#         ctx.logger.app(global__topic_view_increase_num={"ids": ids})
#     except:
#         logging_exception()
#
#     _task_topic_view_increase_num.delay(ids)


@shared_task()
def delayed_activate_callback(url, callback_method=CHANNEL_CALLBACK_TYPE.GET_CALLBACK, idfa=None):
    # params idfa just for log
    res = None

    if callback_method == CHANNEL_CALLBACK_TYPE.GET_CALLBACK:
        res = requests.get(url)

    elif callback_method == CHANNEL_CALLBACK_TYPE.POST_CALLBACK:
        res = requests.post(url)

    return res


'''
@shared_task
def record_stat(model_name, field_name, id_name, id_value, amount_field_name, stat_date):
    model = getattr(models, model_name)
    if model_name and field_name and id_name and id_value and stat_date:
        filter_opts = {field_name: id_value, 'stat_date': str(stat_date)}
        records = model.objects.filter(**filter_opts)
        if records.exists():
            # 今日已经存在该统计项，则加1
            record = records[0]
            setattr(record, amount_field_name, getattr(record, amount_field_name) + 1)
            record.save()
        else:
            # 新增
            try:
                record = model()
                record.stat_date = stat_date
                setattr(record, field_name, id_value)
                setattr(record, amount_field_name, 1)
                record.save()
            except IntegrityError:
                return 'error'
        return 'ok'
    else:
        return 'error'
'''
