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

from django.db import IntegrityError
from django.db.models import Q
from django.conf import settings

from api.models.others import User
from api.models.types import POINTS_OPERATION
from point.models import Points, PointActivity

from rpc.decorators import bind_context
from rpc.exceptions import (RPCPermissionDeniedException, RPCIntegrityError,
    RPCNotFoundException)
from rpc.tool.log_tool import info_logger
from rpc.tool.dict_mixin import to_dict

from ..datatables import PointsDT
from ..queries.points import PointsDQ

uri_pre = 'hera/points'


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


@bind_context(uri_pre+'/list')
def points_datatable(ctx, req_data):
    dtobj = PointsDT(Points)
    return dtobj.process(req_data)


@bind_context(uri_pre+'/get')
def points_get(ctx, points_id, options=None):
    try:
        points = Points.objects.get(id=points_id)
    except:
        raise RPCNotFoundException
    if options is None:
        options = {
            'fields': None,
            'excludes': None,
            'expands': None,
        }
    points_data = to_dict(points, **options)
    return points_data


@bind_context(uri_pre+'/edit')
def points_edit(ctx, points_id=None, points_info=None, urls=None):
    if points_info is None:
        return None
    # points_info['link_topic_id'] = points_info.pop('link_topic') or None
    # points_info['link_reply_id'] = points_info.pop('link_reply') or None
    # points_info['link_user_id'] = points_info.pop('link_user') or None
    # points_info['link_order_id'] = points_info.pop('link_order') or None
    points_info['user_id'] = points_info.pop('user')
    try:
        user = User.objects.get(id=points_info['user_id'])
    except:
        info_logger.info(__import__('traceback').format_exc())
        raise RPCNotFoundException

    has_point = user.person.points
    if points_info['operation'] == POINTS_OPERATION.REMOVE and has_point < int(points_info['number']):
        return {
            'code': 0,
            'points_id': points_id
        }

    if points_id is None:
        try:
            points = Points.objects.create(**points_info)
        except IntegrityError:
            raise RPCIntegrityError
    else:
        try:
            points = Points.objects.get(id=points_id)
        except:
            info_logger.info(__import__('traceback').format_exc())
            raise RPCNotFoundException
        for k, v in points_info.iteritems():
            setattr(points, k, v)
        points.save()
    if points.operation == POINTS_OPERATION.ADD:
        user.person.points = user.person.points + int(points.number)
    else:
        user.person.points = user.person.points - int(points.number)
    user.person.save()
    return {
        'code': 1,
        'points_id': points.id
    }


@bind_context(uri_pre + '/points_choices')
def points_choices(ctx, q='', page=1, num=30, initial=None, is_online=False):
    page = int(page)
    num = int(num)

    if initial is not None:
        if isinstance(initial, (list, tuple)):
            qry = Q(id__in=initial)
        else:
            qry = Q(id=initial)
    else:
        qry = Q(id__contains=q) | Q(name__contains=q)
    if is_online:
        qry &= Q(is_online=True)
    query = PointActivity.objects.using(settings.SLAVE_DB_NAME).filter(qry)
    total_count = 0
    start_pos = (page - 1) * num
    start_pos = start_pos if start_pos >= 0 else 0
    results = [
        {
            'id': obj.id,
            'text': u'{}:{}'.format(obj.id, obj.name),
        } for obj in query[start_pos: start_pos + num]
        ]
    return {'total_count': total_count, 'results': results, 'page': page, 'num': num}
