import datetime
import random

from gm_types.gaia import DIARY_CONTENT_LEVEL
from gm_types.mimas import VOTE_TASK_TYPE, TRACTATE_CONTENT_LEVEL

from qa.utils.statistic import get_countdown
from talos.cache.base import fake_vote_cache
from talos.logger import info_logger
from talos.services import UserConvertService
from talos.tasks.tractate import tractate_fake_vote
from talos.tasks.vote import fake_vote


def format_timestamp(_datetime, hour=0, minute=0, second=0):
    return int(_datetime.replace(hour=hour, minute=minute, second=second).timestamp())


class FakeVoteEvent(object):
    # http://wiki.wanmeizhensuo.com/pages/viewpage.action?pageId=27100295
    # 第一部分任务：
    # 达人、医生、机构 有效时间段内，10 minute - 2 hour 任务执行次数(不在9-22时间段内不灌水)
    first_repeat_times = 6
    first_normal_user = 5

    #第二部分任务：任务执行次数取值区间
    # 达人、医生、机构
    second_repeat_times = {
        DIARY_CONTENT_LEVEL.GENERAL: [9, 14],
        DIARY_CONTENT_LEVEL.BETTER: [19, 24],
        DIARY_CONTENT_LEVEL.FINE: [24, 29],
        DIARY_CONTENT_LEVEL.EXCELLENT: [29, 39],
    }
    # 普通用户
    second_repeat_times_normal_user = {
        DIARY_CONTENT_LEVEL.GENERAL: [0, 0],
        DIARY_CONTENT_LEVEL.BETTER: [0, 1],
        DIARY_CONTENT_LEVEL.FINE: [1, 3],
        DIARY_CONTENT_LEVEL.EXCELLENT: [5, 10],
    }

    # 任务执行次数（一天一次，从第二天开始，记为1）
    SECOND_DAY = 1,
    THIRD_DAY = 2,
    FOURTH_DAY = 3,
    FIFTH_DAY = 4,
    SIXTH_DAY = 5,
    SEVENTH_DAY = 6,


# 普通用户 灌水次数控制, 从第二天开始(审核等级不同，灌水次数不同，在这里统一管理)，共七天
"""
第x天: {
    一般：灌水执行次数区间，
    较好：灌水执行次数区间，
    良好：灌水执行次数区间，
    优秀：灌水执行次数区间，
    }
"""
REPEAT_TIMES_RANGE = {
        FakeVoteEvent.SECOND_DAY: {
            DIARY_CONTENT_LEVEL.GENERAL: [2, 4],        # ('3', u'一般')
            DIARY_CONTENT_LEVEL.BETTER: [4, 5],         # ('3.5', u'较好')
            DIARY_CONTENT_LEVEL.FINE: [5, 6],           # ('4', u'良好')
            DIARY_CONTENT_LEVEL.EXCELLENT: [8, 10],     # ('5', u'优秀')
        },
        FakeVoteEvent.THIRD_DAY: {
            DIARY_CONTENT_LEVEL.GENERAL: [2, 3],
            DIARY_CONTENT_LEVEL.BETTER: [3, 4],
            DIARY_CONTENT_LEVEL.FINE: [4, 5],
            DIARY_CONTENT_LEVEL.EXCELLENT: [6, 8],
        },
        FakeVoteEvent.FOURTH_DAY: {
            DIARY_CONTENT_LEVEL.GENERAL: [1, 2],
            DIARY_CONTENT_LEVEL.BETTER: [2, 3],
            DIARY_CONTENT_LEVEL.FINE: [3, 4],
            DIARY_CONTENT_LEVEL.EXCELLENT: [4, 6],
        },
        FakeVoteEvent.FIFTH_DAY: {
            DIARY_CONTENT_LEVEL.GENERAL: [1, 1],
            DIARY_CONTENT_LEVEL.BETTER: [1, 2],
            DIARY_CONTENT_LEVEL.FINE: [2, 3],
            DIARY_CONTENT_LEVEL.EXCELLENT: [2, 4],
        },
        FakeVoteEvent.SIXTH_DAY: {
            DIARY_CONTENT_LEVEL.GENERAL: [1, 1],
            DIARY_CONTENT_LEVEL.BETTER: [1, 1],
            DIARY_CONTENT_LEVEL.FINE: [1, 2],
            DIARY_CONTENT_LEVEL.EXCELLENT: [1, 2],
        },
        FakeVoteEvent.SEVENTH_DAY: {
            DIARY_CONTENT_LEVEL.GENERAL: [1, 1],
            DIARY_CONTENT_LEVEL.BETTER: [1, 1],
            DIARY_CONTENT_LEVEL.FINE: [1, 2],
            DIARY_CONTENT_LEVEL.EXCELLENT: [1, 2],
        },
    }


# 达人、机构  灌水次数控制
SU_REPEAT_TIMES_RANGE = {
        FakeVoteEvent.SECOND_DAY: {
            DIARY_CONTENT_LEVEL.GENERAL: [10, 15],
            DIARY_CONTENT_LEVEL.BETTER: [20, 25],
            DIARY_CONTENT_LEVEL.FINE: [25, 30],
            DIARY_CONTENT_LEVEL.EXCELLENT: [30, 35],
        },
        FakeVoteEvent.THIRD_DAY: {
            DIARY_CONTENT_LEVEL.GENERAL: [8, 10],
            DIARY_CONTENT_LEVEL.BETTER: [15, 20],
            DIARY_CONTENT_LEVEL.FINE: [20, 25],
            DIARY_CONTENT_LEVEL.EXCELLENT: [25, 30],
        },
        FakeVoteEvent.FOURTH_DAY: {
            DIARY_CONTENT_LEVEL.GENERAL: [6, 8],
            DIARY_CONTENT_LEVEL.BETTER: [5, 10],
            DIARY_CONTENT_LEVEL.FINE: [15, 20],
            DIARY_CONTENT_LEVEL.EXCELLENT: [20, 25],
        },
        FakeVoteEvent.FIFTH_DAY: {
            DIARY_CONTENT_LEVEL.GENERAL: [4, 5],
            DIARY_CONTENT_LEVEL.BETTER: [3, 5],
            DIARY_CONTENT_LEVEL.FINE: [10, 15],
            DIARY_CONTENT_LEVEL.EXCELLENT: [15, 20],
        },
        FakeVoteEvent.SIXTH_DAY: {
            DIARY_CONTENT_LEVEL.GENERAL: [1, 3],
            DIARY_CONTENT_LEVEL.BETTER: [4, 5],
            DIARY_CONTENT_LEVEL.FINE: [5, 10],
            DIARY_CONTENT_LEVEL.EXCELLENT: [10, 15],
        },
        FakeVoteEvent.SEVENTH_DAY: {
            DIARY_CONTENT_LEVEL.GENERAL: [1, 2],
            DIARY_CONTENT_LEVEL.BETTER: [2, 4],
            DIARY_CONTENT_LEVEL.FINE: [1, 5],
            DIARY_CONTENT_LEVEL.EXCELLENT: [5, 10],
        },
    }


class VoteTaskTool(object):
    def __init__(self, task_type, cache_client=fake_vote_cache):
        self.cache_cli = cache_client
        self.task_type = task_type

        if self.task_type == VOTE_TASK_TYPE.TRACTATE:
            self.key = 'tr_fake_vote_cache'
        elif self.task_type == VOTE_TASK_TYPE.DIARY:
            self.key = 'd_fake_vote_cache'
        elif self.task_type == VOTE_TASK_TYPE.TOPIC:
            self.key = 't_fake_vote_cache'
        elif self.task_type == VOTE_TASK_TYPE.QUESTION:
            self.key = 'q_fake_vote_cache'

    def get_repeat_times(self, business_id):
        """
        获取任务执行了几次（一天一次）
        :return:
        """
        if self.cache_cli.exist(self.key):
            repeat_times = int(self.cache_cli.hget(self.key, business_id))
            return repeat_times
        return 0

    def update_repeat_times(self, business_id):
        """
        每次执行完灌水任务，计数+1
        :param business_id:
        :return:
        """
        self.cache_cli.hincrby(self.key, int(business_id))

    def cache_key(self, business_id):
        """
        初次触发灌水完成后，入缓存。
        :param business_id:
        :return:
        """
        self.cache_cli.hset(self.key, int(business_id), 1)
        # today = datetime.datetime.today()
        # 过期时间 到第八天的凌晨0点
        # self.cache_cli.expire(
        #     self.key,
        #     (today.replace(hour=0, minute=0, second=0) - today).seconds + 6*24*2600
        # )

    def check_key_is_valid(self, business_id):
        """
        检查key是否还在有效期内(1-7天)
        :param business_id:
        :return:
        """
        operate_times = self.cache_cli.hget(self.key, int(business_id))
        if operate_times:  # 1 <= days <= 6 is valid
            if int(operate_times) > 6:
                info_logger.info(
                    '{}:{}, 点赞灌水任务完成'.format(
                        VOTE_TASK_TYPE.getDesc(key=self.task_type),
                        business_id,
                    ))
                self.cache_cli.hdel(self.key, int(business_id))
                return False
            return True
        else:
            return False

    def get_all_valid_tasks(self):
        all_tasks = self.cache_cli.hgetall(self.key)
        info_logger.info('all_tasks:{}'.format(all_tasks))

        return all_tasks

    def del_cache_key(self, business_id):
        self.cache_cli.hdel(self.key, business_id)


def time_valid_check(now_date):
    if 9 <= now_date.hour < 22:
        return True
    return False


def is_special_user(user_id):
    """
    判断用户的身份(两类): 1、(医生，机构，达人用户) 2、普通用户
    :param user_id:
    :return:
    """
    user_info = UserConvertService.get_user_info_by_user_id(user_id, simple=True)
    membership_level = int(user_info.get('membership_level', 0))
    doctor_id = user_info.get('doctor_id', None)
    hospital_id = user_info.get('hospital_id', None)

    if any([membership_level, doctor_id, hospital_id]):
        return True
    else:
        return False


def need_push():
    """
     是否需要push通知 20%
    :return:
    """
    if random.randint(0, 10) < 2:
        return True
    return False


def fake_vote_v1(task_type, business_id, special_user, content_level):
    """
    第一天的点赞任务单独处理
    :param task_type: 任务类型 帖子，日记本，日记帖，问题...
    :param business_id: 帖子... id
    :param special_user: 是不是特殊类型用户（医生，机构，达人用户）
    :param content_level: 审核等级
    :return:
    """

    # 第一天任务， 分两部分处理
    # 第一部分：如果发帖时间在有效时间段内，灌6/5条点赞记录，不在有效时间段内不灌水，剩余的在第二部分处理
    now_date = datetime.datetime.now()
    is_valid_time = time_valid_check(now_date)
    if not is_valid_time:  # 不在9-22时间段内, 第一天任务不执行，从第二天开始
        fake_vote_tool = VoteTaskTool(cache_client=fake_vote_cache, task_type=task_type)
        fake_vote_tool.cache_key(business_id)
        return

    first_repeat_times = FakeVoteEvent.first_repeat_times if special_user else FakeVoteEvent.first_normal_user
    cds = get_countdown(first_repeat_times, time_range=(10*60, 2*60*60))
    if task_type == VOTE_TASK_TYPE.TRACTATE:
        for index, cd in enumerate(cds):
            if is_valid_time and index <= 3:
                force_push = True
            else:
                force_push = need_push()
            result = tractate_fake_vote.apply_async(
                args=(1, business_id),
                kwargs={'incr_range': [3, 11], "force_push": force_push},
                countdown=cd
            )
            info_logger.info(
                "帖子点赞第一批任务,id:{}, task_id:{},开始执行时间：{}".format(
                    business_id, result.task_id, now_date+datetime.timedelta(seconds=cd)
                )
            )
        info_logger.info("帖子点赞第一批任务完成,id:{}, 任务个数：{}".format(business_id, len(cds)))

    elif task_type == VOTE_TASK_TYPE.TOPIC:
        for index, cd in enumerate(cds):
            if is_valid_time and index <= 3:
                force_push = True
            else:
                force_push = need_push()
            result = fake_vote.apply_async(
                args=(1, business_id),
                kwargs={'incr_range': [2, 20], 'force_push': force_push},
                countdown=cd
            )
            info_logger.info(
                "日记帖点赞第一批任务,id:{}, task_id:{},开始执行时间：{}".format(
                    business_id, result.task_id, now_date + datetime.timedelta(seconds=cd)
                )
            )
        info_logger.info("日记帖点赞第一批任务完成,id:{}, 任务个数：{}".format(business_id, len(cds)))

    # 第二部分任务：
    two_hours_later = now_date + datetime.timedelta(hours=2)
    # 如果两小时以后时间仍然在当天9-20点之间，就将第一天灌水任务执行完, 否则不执行
    if 9 <= two_hours_later.hour < 22 and now_date.day == two_hours_later.day:
        start_time = int(two_hours_later.timestamp())
        end_time = format_timestamp(now_date, hour=2) + 24*60*60
    else:
        # 第一天任务完成 记录到缓存
        fake_vote_tool = VoteTaskTool(cache_client=fake_vote_cache, task_type=task_type)
        fake_vote_tool.cache_key(business_id)
        return

    # elif two_hours_later.hour < 9:  # 当天9点之前，延迟到九点开始
    #     start_time = format_timestamp(now_date, hour=9)
    #     end_time = format_timestamp(now_date, hour=22)
    #
    # else:  # 当天20点之后，延迟到第二天九点开始
    #     start_time = format_timestamp(now_date, hour=9) + 24*60*60
    #     end_time = format_timestamp(now_date, hour=22) + 24*60*60

    # 第二部分的任务剩余量：
    if special_user:
        repeat_range = FakeVoteEvent.second_repeat_times.get(str(content_level), [0, 0])
        second_repeat_times = random.randint(
            repeat_range[0], repeat_range[1]
        )
    else:
        repeat_range = FakeVoteEvent.second_repeat_times_normal_user.get(str(content_level), [0, 0])
        second_repeat_times = random.randint(
            repeat_range[0], repeat_range[1]
        )
    time_range = (start_time, end_time)
    cds = get_countdown(second_repeat_times, time_range=time_range)
    if task_type == VOTE_TASK_TYPE.TRACTATE:
        for cd in cds:
            force_push = need_push()
            result = tractate_fake_vote.apply_async(
                args=(1, business_id),
                kwargs={'incr_range': [3, 11], "force_push": force_push},
                eta=datetime.datetime.fromtimestamp(cd - 8*3600)
            )
            info_logger.info(
                "帖子点赞第二批任务,id:{}, task_id:{},开始执行时间：{}".format(
                    business_id, result.task_id, datetime.datetime.fromtimestamp(cd)
                )
            )
        info_logger.info("帖子点赞第二批任务完成,id:{}, 任务个数：{}".format(business_id, len(cds)))

    elif task_type == VOTE_TASK_TYPE.TOPIC:
        for cd in cds:
            force_push = need_push()
            result = fake_vote.apply_async(
                args=(1, business_id),
                kwargs={'incr_range': [2, 20], 'force_push': force_push},
                eta=datetime.datetime.fromtimestamp(cd - 8 * 3600)
            )
            info_logger.info(
                "日记帖点赞第二批任务,id:{}, task_id:{},开始执行时间：{}".format(
                    business_id, result.task_id, datetime.datetime.fromtimestamp(cd)
                )
            )
        info_logger.info("日记帖点赞第二批任务完成,id:{}, 任务个数：{}".format(business_id, len(cds)))

    # 第一天任务完成 记录到缓存
    fake_vote_tool = VoteTaskTool(cache_client=fake_vote_cache, task_type=task_type)
    fake_vote_tool.cache_key(business_id)
