# -*- coding: UTF-8 -*-

from __future__ import absolute_import

import datetime
import re

from django.db import IntegrityError, transaction
from django.db.models import Q
from gm_types.gaia import PUSHCOUPON_STATUS

from rpc.decorators import bind_context
from rpc.exceptions import (RPCPermissionDeniedException, RPCIntegrityError,
                            RPCNotFoundException, GaiaRPCFaultException)
from rpc.tool.dict_mixin import to_dict
from api.models.pushtask import PushTask, PushtaskCity, PushtaskRegion, PushtaskTag, PushtaskPolymer, PushtaskQAAlert
from api.models import Region, City, Tag, Polymer
from api.models.pushtask import PushCoupon
from api.tasks.push_task import pushtask_coupon
from hera.views.privatemessagepush import get_duration
from ..queries.pushtask import PushTaskDQ
from talos.models.live import LiveChannel
from rpc.context import get_rpc_remote_invoker
from api.tool.log_tool import logging_exception

from rpc.tool.log_tool import info_logger

__author__ = 'Zyy'

uri_pre = 'hera/pushtask'


@bind_context(uri_pre + '/query')
def pushtask_query(ctx, options):
    dqobj = PushTaskDQ()
    return dqobj.process(**options)


@bind_context(uri_pre + '/get')
def pushtask_detail(ctx, pushtask_id, options=None):
    '''
        获取推送任务
    '''
    try:
        pushtask = PushTask.objects.get(id=pushtask_id)
        if pushtask.question_id or pushtask.answer_id:
            try:
                _ = PushtaskQAAlert.objects.get(pushtask_qa_id=pushtask_id)
                if not _.have_alert:
                    pushtask.alert = ""
            except:
                logging_exception()
    except:
        raise RPCNotFoundException
    if options is None:
        options = {
            'fields': None,
            'excludes': None,
            'expands': None,
        }
    pushtask_data = to_dict(pushtask, **options)
    return pushtask_data


@bind_context(uri_pre + '/edit')
@transaction.atomic
def pushtask_edit(ctx, pushtask_id=None, pushtask_info=None):
    '''
        编辑推送
    '''
    rpc_invoker = get_rpc_remote_invoker()
    if pushtask_info is None:
        return None
    user = ctx.session.user


    have_alert = True if pushtask_info.get('alert') else False
    pushtask_info['service_id'] = pushtask_info.pop('service')
    pushtask_info['special_id'] = pushtask_info.pop('special')
    pushtask_info['tag_id'] = pushtask_info.pop('tag')
    pushtask_info['zhibo_user_id'] = pushtask_info.pop('zhibo_user')
    if pushtask_info.get('answer_id') and not pushtask_info.get('alert'):
        q_a = rpc_invoker['qa/answer/question_info'](answer_id=pushtask_info.get('answer_id')).unwrap()
        pushtask_info['alert'] = q_a.get('question_title', '')
        have_alert = False
    if pushtask_info.get('question_id') and not pushtask_info.get('alert'):
        q_a = rpc_invoker['qa/question/detail'](question_id=pushtask_info.get('question_id')).unwrap()
        pushtask_info['alert'] = q_a.get('title', '')
    for key in ['diary_id', 'topic_id', 'activity_id', 'article_id', 'question_id', 'answer_id']:
        pushtask_info[key] = pushtask_info.pop(key) or None

    region_ids = pushtask_info.pop('region')
    city_ids = pushtask_info.pop('city')
    tag_ids = pushtask_info.pop('push_tags')
    polymer_ids = pushtask_info.pop('polymer')

    if pushtask_id is None:
        try:
            pushtask = PushTask.objects.create(**pushtask_info)
            pushtask.creator = user
            pushtask.save()
            
            if pushtask_info.get('answer_id'):
                PushtaskQAAlert.objects.create(pushtask_qa_id=pushtask.id, have_alert=have_alert)
            if pushtask_info.get('question_id'):
                PushtaskQAAlert.objects.create(pushtask_qa_id=pushtask.id, have_alert=have_alert)
        except IntegrityError:
            raise RPCIntegrityError
    else:
        try:
            pushtask = PushTask.objects.get(id=pushtask_id)
            if pushtask_info.get('answer_id'):
                qa_push, is_new = PushtaskQAAlert.objects.get_or_create(pushtask_qa_id=pushtask.id)
                qa_push.have_alert = have_alert
                qa_push.save(update_fields=['have_alert'])
            if pushtask_info.get('question_id'):
                qa_push, is_new = PushtaskQAAlert.objects.get_or_create(pushtask_qa_id=pushtask.id)
                qa_push.have_alert = have_alert
                qa_push.save(update_fields=['have_alert'])
        except:
            info_logger.info(__import__('traceback').format_exc())
            raise RPCNotFoundException
        for k, v in pushtask_info.iteritems():
            if v == u'':
                continue
            setattr(pushtask, k, v)
        pushtask.save()

    new_region = set(Region.objects.filter(id__in=region_ids))
    old_region = set(pushtask.region.all())
    for region in (new_region - old_region):
        PushtaskRegion.objects.get_or_create(pushtask=pushtask, region=region)
    PushtaskRegion.objects.filter(pushtask=pushtask, region__in=(old_region-new_region)).delete()

    new_city = set(City.objects.filter(id__in=city_ids))
    old_city = set(pushtask.city.all())
    for city in (new_city - old_city):
        PushtaskCity.objects.get_or_create(pushtask=pushtask, city=city)
    PushtaskCity.objects.filter(pushtask=pushtask, city__in=(old_city-new_city)).delete()

    new_tag = set(Tag.objects.filter(id__in=tag_ids))
    old_tag = set(pushtask.push_tags.all())
    for tag in (new_tag - old_tag):
        PushtaskTag.objects.get_or_create(pushtask=pushtask, tag=tag)
    PushtaskTag.objects.filter(pushtask=pushtask, tag__in=(old_tag-new_tag)).delete()

    new_polymer = set(Polymer.objects.filter(id__in=polymer_ids))
    old_polymer = set(pushtask.polymer.all())
    for polymer in (new_polymer - old_polymer):
        PushtaskPolymer.objects.get_or_create(pushtask=pushtask, polymer=polymer)
    PushtaskPolymer.objects.filter(pushtask=pushtask, polymer__in=(old_polymer - new_polymer)).delete()

    return pushtask.id


@bind_context(uri_pre + '/get_info')
def pushtask_get_info(ctx, items):
    '''
        通过pushtask的ids获得任务列表
    '''
    rpc_invoker = get_rpc_remote_invoker()
    info = []
    list = PushTask.objects.filter(id__in=items)
    for pushtask in list:
        temp = to_dict(pushtask)
        temp['tag_name'] = pushtask.tag.name if pushtask.tag else ''
        temp['special_type'] = pushtask.special.type if pushtask.special else ''
        temp['alert'] = pushtask.alert if pushtask.alert else ''

        if temp.get('polymer'):
            temp['users'] = PushTask.get_pushuser_by_polymer(temp.get('polymer')).get('user')
        if not temp.get('alert') and temp.get('question_id'):
            try:
                _ = PushtaskQAAlert.objects.get(pushtask_qa_id=pushtask.id)
                if not _.have_alert:
                    question = rpc_invoker['qa/question/detail'](question_id=temp['question_id']).unwrap()
                    temp['alert'] = question.get('title')
            except:
                logging_exception()
        if temp.get('answer_id'):
            try:
                _ = PushtaskQAAlert.objects.get(pushtask_qa_id=pushtask.id)
                if not _.have_alert:
                    q_a = rpc_invoker['qa/answer/question_info'](answer_id=temp['answer_id']).unwrap()
                    temp['push_style_bold'] = True
                    body = q_a.get('answer_content', '').lstrip('<p>').rstrip('</p>')
                    body = re.sub('<[^>]+>', '', body)
                    body = body[:45] + ('...' if len(body) > 45 else '')
                    temp['alert'] = {
                        'title': q_a.get('question_title', ''),
                        'body': body
                    }
            except:
                logging_exception()
        if pushtask.zhibo_user:
            person_id = pushtask.zhibo_user.person.id.hex
            livechannel = LiveChannel.objects.filter(person_id=person_id).first()
            temp['zhibo_channal_id'] = livechannel.id if livechannel else None
        info.append(temp)
    return info


@bind_context(uri_pre + '/pass')
def pushtask_pass(ctx, items):
    '''
        任务审核
    '''
    user = ctx.session.user
    list = PushTask.objects.filter(id__in=items)
    list.update(approver=user)
    return items


@bind_context(uri_pre + '/retry_pass')
def pushtask_pass(ctx, pushtask_id):
    '''
        取消审核
    '''
    pushtask = PushTask.objects.get(id=pushtask_id)
    pushtask.approver=None
    pushtask.eta = datetime.datetime.now()
    pushtask.save()




@bind_context(uri_pre + '/coupon/pass')
def pushtask_coupon_pass(ctx, id):
    '''
        美券推送
    '''
    p = PushCoupon.objects.get(id=id)
    if not p.status == PUSHCOUPON_STATUS.DEFAULT:
        raise GaiaRPCFaultException(error=1, message=u'推送状态不正确', data=None)
    if p.eta <= datetime.datetime.now():
        raise GaiaRPCFaultException(error=1, message=u'推送时间不正确', data=None)
    else:
        p.status = PUSHCOUPON_STATUS.PASS
        p.save()
        duration = get_duration(p.eta)
        pushtask_coupon.apply_async((p.id,), countdown=duration)
