# coding=utf-8
from __future__ import absolute_import, print_function, unicode_literals

import random
import datetime

from datetime import timedelta
from celery import shared_task
from gm_types.gaia import CONST_STRINGS as const_strings
from gm_types.push.enum import AUTOMATED_PUSH
from gm_types.mimas import NOTICATION_LIST_CATEGORY
from gm_types.push import PUSH_INFO_TYPE
from six.moves import xrange
from gm_protocol import GmProtocol

from qa.utils.statistic import get_async_args_v2
from talos.cache.base import diary_pv_cache
from talos.models.diary import Diary
from talos.models.diary import DiaryVote
from talos.models.topic import TopicVote
from talos.services.user import UserService
from utils.protocol import gm_protocol
from utils.push import vote_push, push_task_to_user_multi
from utils.rpc import rpc_client
from .tasks import view_increase, view_increase_amount
from ..models.topic import Problem
from talos.cache.base import fake_vote_cache
from talos.tools.vote_tool import VoteTool
from talos.cache.base import vote_cache
from talos.manager.diary import diary_list_manager
from communal.tasks import intelligent_push_task
from talos.services.other import get_user_lastest_device_app_version_by_user_id
from utils.common import is_version_gray


_MAX_SLEEP_PERSON = 5000


def get_fake_view_num(start, end):
    return random.randint(start, end)


def get_sleep_user(repeat_times):
    user_ids = rpc_client['api/user/get_sleep_user'](number=repeat_times).unwrap()
    return user_ids


def normal_vote(user, item, is_diary=False, incr_range=[5, 15]):
    """
    :param user: 点赞的用户
    :param item: 日记本或者日记贴
    :param is_diary: 是否日记本
    :param incr_range: 浏览量增加的范围
    :return:
    """
    if is_diary:
        diary = item
        like_num = diary.like_num
        # 增加点赞数
        diary.like_num += 1
        diary.save()

        # 增加浏览量
        fake_view_num = get_fake_view_num(*incr_range)
        diary_pv_cache.incrby(str(diary.id), fake_view_num)

        # 点赞推送  日记本点赞进入防干扰
        alert = u'有1位朋友给你点了赞，快来看看吧>>'
        push_url = GmProtocol().get_diary_detail(id=diary.id)
        version = get_user_lastest_device_app_version_by_user_id(diary.user_id)
        # 推送跳转到消息页的赞列表
        if is_version_gray(version, '7.29.0'):
            push_url = GmProtocol().vote_or_favor_list(
                segment_index=NOTICATION_LIST_CATEGORY.VOTE,
                new_vote=True,
            )
        intelligent_push_task.delay(
            content_id=diary.id,
            user_ids=[diary.user_id],
            push_type=AUTOMATED_PUSH.DIARY_RECEIVED_PRAISE,
            platform=None,
            extra={
                'type': PUSH_INFO_TYPE.GM_PROTOCOL,
                'pushUrl': push_url,
                'push_url': push_url,
            },
            alert=alert,
            others={
                "title": "@{} 给你点了赞".format(user.nick_name),
                "alert": alert,
            },
            labels={},
        )
    else:
        topic = item
        # 增加点赞数
        view_increase(Problem.get_redis_vote_key(), topic.id)
        if topic.diary_id:
            # 增加对应的日记点赞数
            view_increase(Diary.get_redis_diary_topic_vote_key(), topic.diary_id)
        # 增加浏览量
        view_increase_amount(const_strings.TOPIC_VIEW, topic.id, get_fake_view_num(*incr_range))
        #topic.diary.operation_time 手术时间  topic.operation_date
        if not topic.diary or not topic.diary.operation_time or not topic.operation_date:
            return

        end, start = topic.operation_date, topic.diary.operation_time

        days = (end.replace(hour=0, minute=0, second=0, microsecond=0) -
                start.replace(hour=0, minute=0, second=0, microsecond=0)).days
        diary_title = u'{diary_title}（第{days}天）'.format(diary_title=topic.diary.title, days=days)
        alert = u'{user_name}刚刚赞了你的《{diary_title}》，比心~'.format(user_name=str(user.nick_name),
                                                                       diary_title=diary_title)
        push_url = GmProtocol().get_topic_detail(id=topic.id)
        user_id = topic.user_id
        version = get_user_lastest_device_app_version_by_user_id(user_id)
        # 推送跳转到消息页的赞列表
        if is_version_gray(version, '7.29.0'):
            push_url = GmProtocol().vote_or_favor_list(
                segment_index=NOTICATION_LIST_CATEGORY.VOTE,
                new_vote=True,
            )
        vote_push(user_id=user_id, alert=alert, push_type=AUTOMATED_PUSH.DIARY_POST_RECEIVED_PRAISE, push_url=push_url)


@shared_task
def fake_vote(repeat_times, item_id, need_view_increase=True, incr_range=[1, 1], is_topic=True, force_push=False, author_name=None,
              topic_title=None):
    """
    Get random {amount} users who's last login time earlier than 2015,and let them vote for topic each person one time
    :param repeat_times:
    :param topic:
    :param need_view_increase
    :param incr_num 增加多少浏览数
    :param is_topic
    :return:
    """
    # 获取沉睡用户
    user_extras = get_sleep_user(repeat_times)

    if is_topic:
        return fake_vote_topic(user_extras, item_id, need_view_increase, incr_range, force_push, author_name, topic_title)
    return fake_vote_diary(user_extras, item_id, need_view_increase, incr_range, force_push)


def fake_vote_diary(users, diary_id, need_view_increase=True, incr_range=[1, 1], force_push=False):
    diary = Diary.objects.get(pk=diary_id)

    # 帖子下线, 不处理
    if not diary.is_online:
        return

    diary_fake_vote_key = "diary_fake_vote_{id}".format(id=diary_id)
    is_set = fake_vote_cache.set(diary_fake_vote_key, 1, nx=True, ex=30)
    if not is_set:
        return

    cnt, u_nick_name = 0, ''
    for ue in users:
        _, created = DiaryVote.objects.get_or_create(user_id=ue, diary_id=diary.id, is_fake=True)
        if created:
            # 对日记本作者增加点赞数
            u = UserService.get_user_by_user_id(diary.user_id)
            u.incr_vote_count()
            if not u_nick_name:
                vote_user = UserService.get_user_by_user_id(ue)
                u_nick_name = vote_user.nickname
            cnt += 1

    if not need_view_increase:
        return

    # 增加可视点赞数
    like_num = diary.like_num
    before_fake = like_num
    diary.like_num += cnt
    diary.save()
    after_fake = diary.like_num

    view_num = 0

    # 每个点赞增加随机浏览量
    for i in xrange(cnt):
        view_num += random.randint(*incr_range)

    # 增加可视浏览数
    diary_pv_cache.incrby(str(diary.id), view_num)
    if force_push:
        alert = u'{user_name} 刚刚感谢了你的《{diary_title}》，比心~'.format(user_name=u_nick_name, diary_title=diary.title)
        push_url = GmProtocol().get_diary_detail(id=diary.id)
        vote_push(diary.user_id, alert=alert, push_type=AUTOMATED_PUSH.DIARY_RECEIVED_PRAISE, push_url=push_url)


def fake_vote_topic(userids, topic_id, need_view_increase=True, incr_range=[1, 1], force_push=False, author_name=None, topic_title=None):
    # reload data from db

    now_date = datetime.datetime.now()
    if not 9 <= now_date.hour < 22:  # 超过晚十点灌水任务不执行
        return
    topic_fake_vote_key = "topic_fake_vote_{id}".format(id=topic_id)
    is_set = fake_vote_cache.set(topic_fake_vote_key, 1, nx=True, ex=30)
    if not is_set:
        return

    topic = Problem.objects.get(pk=topic_id)
    if not topic.is_online:
        return

    cnt, u_nick_name = 0, ''
    # 增加可视的点赞数
    before_fake = topic.vote_amount
    view_increase_amount(const_strings.TOPIC_VOTE, topic.id, cnt)
    after_fake = topic.vote_amount

    for ue in userids:
        if topic.is_offline:
            continue

        topic_vote, created = TopicVote.objects.get_or_create(
            user_id=ue, topic_id=topic.id, is_fake=True, topic_author_id=topic.user_id,
        )

        if created:
            # 对日记作者增加点赞数
            u = UserService.get_user_by_user_id(topic.user_id)
            u.incr_vote_count()
            if not u_nick_name:
                vote_user = UserService.get_user_by_user_id(ue)
                u_nick_name = vote_user.nickname
            cnt += 1
            view_increase(Problem.get_redis_vote_key(), topic.id)

            if need_push(before_fake, after_fake, force_push=force_push):
                view_increase(Problem.get_redis_vote_key(), topic.id)
                alert = u'{user_name}刚刚赞了你的《{diary_title}》，比心~'.format(
                    user_name=u_nick_name, diary_title=topic.diary.title)
                push_url = GmProtocol().get_topic_detail(id=topic_id)
                vote_push(user_id=topic.user_id, alert=alert, is_force=force_push, push_url=push_url,
                          push_type=AUTOMATED_PUSH.DIARY_POST_RECEIVED_PRAISE)

    if not need_view_increase:
        return

    # 为每个点赞数增加可视浏览数
    for i in xrange(cnt):
        fake_view_topic(topic.id, incr_range)


@shared_task
def fake_view_topic(topic_id, incr_range=[1, 1]):
    """
    增加帖子浏览量
    :param topic:
    :return:
    """
    incr_num = get_fake_view_num(*incr_range)
    view_increase_amount(const_strings.TOPIC_VIEW, topic_id, incr_num)


def need_push(before, after, force_push=False):
    # 放大后点赞数超整10, 或者不满十个赞但需要强制推送
    before = int(before)
    after = int(after)
    return (after / 10 - before / 10) >= 1 or (after < 10 and force_push)


def process_topic_vote_for_create(topic_id):
    """
    处理创建日记贴之后的点赞和增加浏览量
    :param topic:
    :return:
    """
    # 异步增加点赞数和浏览量
    # 规则1, 发帖[30s, 60s], 增加浏览量
    countdown, incr_range = get_async_args_v2(const_strings.TOPIC_VOTE_RULE1)
    fake_view_topic.apply_async(args=(topic_id,),
                                kwargs={'incr_range': incr_range},
                                countdown=countdown[0])

    countdowns, incr_range = get_async_args_v2(const_strings.CREATE_TOPIC_VOTE)
    for index, cd in enumerate(countdowns):
        task_info = fake_vote.apply_async(args=(1, topic_id),
                                          kwargs={'incr_range': incr_range, 'force_push': True},
                                          countdown=cd
                                          )

        from talos.logger import qiniu_logger
        qiniu_logger.info("task_id====={task_id}".format(task_id=task_info.task_id))


@shared_task
def diary_push_timing():
    # 灌水1.0上线 下线所有之前的灌水逻辑
    return
