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

import json
from django.db import IntegrityError
from django.db.models import Q
from django.conf import settings
from django.utils.timezone import now
from rpc.decorators import bind_context
from rpc.exceptions import (RPCIntegrityError, RPCNotFoundException)
from rpc.tool.dict_mixin import to_dict
from api.models import CampaignGift
from api.models import Campaign, CampaignImageLink, CampaignLayout, CAMPAIGN_MODULE, CampaignCouponPage
from ..utils import get_choices
from ..datatables import CampaignDT, CampaignImageLinkDT
from rpc.tool.log_tool import info_logger, logging_exception
from hera.utils import model_edit
from ..queries.campaign import CampaignDQ, CampaignImageLinkDQ

uri_pre = 'hera/campaign'


@bind_context(uri_pre + '/choices')
def campaign_choices(ctx, q='', page=1, num=30, initial=None):
    src_map = {'id': 'id', 'text': 'name'}
    if initial is None:
        qry_item = {'key': 'name', 'val': q}
        fetch_seleted = False
    else:
        qry_item = {'key': 'id', 'val': initial}
        fetch_seleted = True
    if fetch_seleted:
        # get initial options
        if isinstance(qry_item['val'], (list, tuple)):
            qs = {'{}__in'.format(qry_item['key']): qry_item['val']}
        else:
            qs = {qry_item['key']: qry_item['val']}
        q = Q(**qs)
    else:
        qs = {'{}__contains'.format(qry_item['key']): qry_item['val']}
        q = Q(online_time__gt=now())
        q &= Q(**qs)
    query = Campaign.objects.using(settings.SLAVE_DB_NAME).filter(q)
    return get_choices(query, page, num, src_map)


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


@bind_context(uri_pre + '/list')
def campaign_datatable(ctx, req_data):
    dtobj = CampaignDT(Campaign)
    return dtobj.process(req_data)


@bind_context(uri_pre + '/get')
def campaign_detail(ctx, campaign_id, options=None):
    try:
        campaign = Campaign.objects.get(id=campaign_id)
    except:
        raise RPCNotFoundException
    if options is None:
        options = {
            'fields': None,
            'excludes': None,
            # 'expands': {"share":["title", "content", "moments", "weibo", "image"]},
            'expands': None,
        }
    campaign_data = to_dict(campaign, **options)
    campaign_data['layouts'] = {}
    for layout in campaign.campaignlayout_set.all():
        if layout.related:
            if layout.module != CAMPAIGN_MODULE.DESCRIPTION \
                    and layout.module != CAMPAIGN_MODULE.DESCRIPTION2 \
                    and layout.module != CAMPAIGN_MODULE.DESCRIPTION3:
                related = json.loads(layout.related)
            else:
                related = layout.related
        else:
            related = ''
        layout_data = {
            'id': layout.id,
            'is_visible': layout.is_visible,
            'ordering': layout.ordering,
            'related': related,
        }
        campaign_data['layouts'][layout.module] = layout_data
    return campaign_data


@bind_context(uri_pre + '/edit')
def campaign_edit(ctx, campaign_id=None, campaign_info=None):
    if campaign_info is None:
        return None
    campaign_info["share_id"] = campaign_info.pop("share")
    campaign = model_edit(Campaign, campaign_id, campaign_info)
    return {'id': campaign.id}


@bind_context(uri_pre + '/set_is_online')
def set_is_online(ctx, campaign_id, is_online):
    try:
        campaign = Campaign.objects.get(id=campaign_id)

    except:
        info_logger.info(__import__('traceback').format_exc())
        raise RPCNotFoundException
    campaign.is_online = is_online
    campaign.save()
    return {'success': True}


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


@bind_context(uri_pre + '/link/list')
def link_datatable(ctx, req_data):
    dtobj = CampaignImageLinkDT(CampaignImageLink)
    return dtobj.process(req_data)


@bind_context(uri_pre + '/link/choices')
def link_choices(ctx, q='', page=1, num=30, initial=None, module_type=None):
    if initial is None:
        qry_item = {'key': 'name', 'val': q}
        fetch_seleted = False
    else:
        qry_item = {'key': 'id', 'val': initial}
        fetch_seleted = True
    if fetch_seleted:
        # get initial options
        if isinstance(qry_item['val'], (list, tuple)):
            qs = {'{}__in'.format(qry_item['key']): qry_item['val']}
        else:
            qs = {qry_item['key']: qry_item['val']}
        q = Q(**qs)
    else:
        qs = {'{}__contains'.format(qry_item['key']): qry_item['val']}
        q = Q(**qs)
        if module_type:
            q &= Q(module_type=module_type)
    query = CampaignImageLink.objects.using(settings.SLAVE_DB_NAME).filter(q)
    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}


@bind_context(uri_pre + '/link/get')
def link_detail(ctx, link_id, options=None):
    try:
        link = CampaignImageLink.objects.get(id=link_id)
    except:
        raise RPCNotFoundException
    if options is None:
        options = {
            'fields': None,
            'excludes': None,
            'expands': None,
        }
    link_data = to_dict(link, **options)
    return link_data


@bind_context(uri_pre + '/link/edit')
def link_edit(ctx, link_id=None, link_info=None):
    if link_info is None:
        return None

    for key in ['topic_id', 'service', 'diary_id', 'tag', 'activity_id', 'special']:
        link_info['{}_id'.format(key) if '_id' not in key else key] = link_info.pop(key) or None

    link = model_edit(CampaignImageLink, link_id, link_info)
    return link.id


@bind_context(uri_pre + '/layout/edit')
def layout_edit(ctx, layout_id=None, layout_info=None):
    if layout_info is None:
        return None
    if CampaignLayout.objects.filter(module=layout_info['module'], campaign_id=layout_info['campaign_id']):
        try:
            layout = CampaignLayout.objects.get(id=layout_id)
        except:
            info_logger.info(__import__('traceback').format_exc())
            raise RPCNotFoundException
        for k, v in layout_info.iteritems():
            setattr(layout, k, v)
        layout.save()
    else:
        try:
            layout_info.pop('id')
            layout = CampaignLayout.objects.create(**layout_info)
        except IntegrityError:
            raise RPCIntegrityError
        except:
            raise
    return layout.id


@bind_context(uri_pre + '/campaigncouponpage/get')
def campaigncouponpage(ctx, campaign_id, options=None):
    try:
        campaigncouponpages = CampaignCouponPage.objects.filter(campaign_id=campaign_id)
    except:
        raise
    if campaigncouponpages.count() == 0:
        return None
    if options is None:
        options = {
            'fields': None,
            'excludes': None,
            'expands': None,
        }
    campaigncouponpage_data = to_dict(campaigncouponpages[0], **options)
    return campaigncouponpage_data


@bind_context(uri_pre + '/campaigncouponpage/edit')
def campaigncouponpage_edit(ctx, campaigncouponpage_id=None, campaigncouponpage_info=None):
    if campaigncouponpage_info is None:
        return None
    if campaigncouponpage_id is None:
        try:
            campaigncouponpage = CampaignCouponPage.objects.create(**campaigncouponpage_info)
        except IntegrityError:
            raise RPCIntegrityError
    else:
        try:
            campaigncouponpage = CampaignCouponPage.objects.get(id=campaigncouponpage_id)
        except:
            logging_exception()
            raise RPCNotFoundException
        for k, v in campaigncouponpage_info.iteritems():
            setattr(campaigncouponpage, k, v)
        campaigncouponpage.save()
    return {"campaigncouponpage_id": campaigncouponpage.id}


@bind_context(uri_pre + '/campaigngift/get')
def campaigngift(ctx, campaigncouponpage_id, options=None):
    try:
        campaigncouponpage = CampaignGift.objects.filter(campaigncouponpage_id=campaigncouponpage_id)
    except:
        raise RPCNotFoundException
    if options is None:
        options = {
            'fields': None,
            'excludes': None,
            'expands': None,
        }
    campaigncouponpage_data = [to_dict(obj) for obj in campaigncouponpage]
    return campaigncouponpage_data


@bind_context(uri_pre + '/campaigngift/edit')
def edit_campaigncoupon(ctx, campaigncouponpage_id, campaigngift_info):
    """
    新增或者编辑活动美券大礼包跳转
    """
    CampaignGift.objects.filter(campaigncouponpage__id=campaigncouponpage_id)\
        .exclude(gift_id__in=[x["gift"] for x in campaigngift_info])\
        .delete()

    for info in campaigngift_info:
        gift = CampaignGift.objects.get_or_create(
            campaigncouponpage_id=campaigncouponpage_id, gift_id=info["gift"])[0]
        gift.ordering = info["ordering"]
        gift.save()

    return {"campaigncouponpage_id": campaigncouponpage_id}
