# coding=utf-8

from __future__ import absolute_import, unicode_literals, print_function
from collections import namedtuple
from talos.models.topic import Problem
from django.utils import timezone
from .node import AdhocNode
from .topic import CreatedTimeNode, UserRelatedTagNode, ViewCountNode, VoteCountNode, ReplyCountNode, HasServiceNode
from rpc.cache import topic_sug_cache
from search.tasks.suggest_topic_test import calc_topic_chunk
from search.utils.task_chunk import get_task_chunk_field
import hashlib
import json

TopicCalcExtParams = namedtuple('TopicCalcExtParams', [
    'user_related_tag_ids', # 用户关注的tag id list
    'now', # 当前时间
])


def suggest_topic_test(calc_params):
    calc_params['created_time']['alpha'], calc_params['created_time']['beta'] = CreatedTimeNode.solve_params(
        calc_params['created_time']['x1']*3600, calc_params['created_time']['y1'],
        calc_params['created_time']['x2']*3600, calc_params['created_time']['y2'])

    node = AdhocNode.build((
        1.0, [
            CreatedTimeNode(
                weight=calc_params['created_time']['weight'],
                alpha=calc_params['created_time']['alpha'],
                beta=calc_params['created_time']['beta']),
            UserRelatedTagNode(
                weight=calc_params['user_related_tag']['weight'],
                not_related_value=calc_params['user_related_tag']['not_related_value']),
            ViewCountNode(
                weight=calc_params['view_count']['weight'],
                thres=calc_params['view_count']['thres'],
                base=calc_params['view_count']['base'],
                coeff=calc_params['view_count']['coeff'],
                pw=calc_params['view_count']['power']),
            VoteCountNode(
                weight=calc_params['vote_count']['weight'],
                thres=calc_params['vote_count']['thres'],
                base=calc_params['vote_count']['base'],
                coeff=calc_params['vote_count']['coeff'],
                pw=calc_params['vote_count']['power']),
            ReplyCountNode(
                weight=calc_params['reply_count']['weight'],
                thres=calc_params['reply_count']['thres'],
                base=calc_params['reply_count']['base'],
                coeff=calc_params['reply_count']['coeff'],
                pw=calc_params['reply_count']['power']),
            HasServiceNode(
                weight=calc_params['has_service']['weight'],
                not_service_value=calc_params['has_service']['not_service_value']),
        ]
    ))
    now = timezone.now()
    ext_params = TopicCalcExtParams(
        user_related_tag_ids=calc_params['user_related_tag']['user_related_tag_ids'],
        now=now)

    # slice topics into chunk tasks
    task_id = hashlib.md5(now.isoformat()).hexdigest()
    chunk_count = 0
    offset = 0
    chunk_size = 10000
    while True:
        topics = Problem.objects.order_by('pk').filter(pk__gt=offset)[:chunk_size]
        if not topics.exists():
            break
        calc_topic_chunk.delay(task_id, chunk_count, node, ext_params, offset, chunk_size)
        chunk_count += 1
        offset = list(topics.values_list('pk', flat=True))[-1]

    task_info = {
        'task_id':task_id,
        'chunk_count':chunk_count,
    }
    topic_sug_cache.hset(task_id, 'info', json.dumps(task_info))
    topic_sug_cache.expire(task_id, 86400) # expire in one day
    return {'task_id':task_id}


def merge_topic_chunks(task_id):
    SHOW_SIZE = 100
    task_info = topic_sug_cache.hget(task_id, 'info')

    if task_info is None: # no such task or out of date
        return {'status':2}

    task_info = json.loads(task_info)
    if 'topic_list' in task_info: # already done
        return {
            'status':0,
            'topics':task_info['topic_list'],
        }

    chunk_count = task_info['chunk_count']
    result = []
    for chunk_id in range(chunk_count):
        chunk_result = topic_sug_cache.hget(task_id, get_task_chunk_field(chunk_id))
        if chunk_result is None:
            return {'status':1}
        result += json.loads(chunk_result)

    result = sorted(result, key=lambda x:x['total'], reverse=True)
    result_iter = iter(result)
    topic_id_set = set() # ensure no duplicate entry
    topic_list = []

    while len(topic_list) < SHOW_SIZE:
        try:
            topic = result_iter.next()
            if topic['topic_id'] in topic_id_set:
                continue
            topic_list.append(topic)
            topic_id_set.add(topic['topic_id'])
        except StopIteration:
            break

    task_info['topic_list'] = topic_list
    topic_sug_cache.hset(task_id, 'info', json.dumps(task_info))

    return {
        'status':0,
        'topics':topic_list,
    }
