# encoding=utf-8
from __future__ import unicode_literals

import datetime

from django.db import IntegrityError,transaction
from django.db.models import Q

from api.models.area import City
from api.models import SeoDigest,SeoCategory,CategoryRelation,FriendlySite,InnerHyperlink
from hera.queries.seo import SeoDigestDQ,SeoCategoryDQ,FriendlySiteDQ,InnerHyperlinkDQ
from hera.utils import model_edit
from rpc.decorators import bind_context
from rpc.exceptions import RPCIntegrityError, RPCNotFoundException
from rpc.tool.dict_mixin import to_dict
from rpc.tool.log_tool import info_logger, logging_exception
from hera.queries.choice_query import choice_query
from gm_types.gaia import CATEGORY_TYPE


__author__ = 'Yang Zhou'


uri_pre = 'hera/seodigest'
seo_pre = 'hera/seocategory'
fri_pre = 'hera/friendlysite'
inn_pre = 'hera/innerhyperlink'


@bind_context(uri_pre + '/list')
def seodigest_list(ctx, options):
    dtobj = SeoDigestDQ()
    return dtobj.process(**options)


@bind_context(uri_pre + '/get')
def seodigest_detail(ctx, seodigest_id, options=None):
    try:
        seodigest_info = SeoDigest.objects.get(id=seodigest_id)
    except:
        raise RPCNotFoundException
    if options is None:
        options = {
            'fields': None,
            'excludes': None,
            'expands': None,
        }
    data = to_dict(seodigest_info, **options)
    return data


@bind_context(uri_pre + '/modify')
def seodigest_modify(ctx, seodigest_id=None, seodigest_info=None):
    res = {}
    seodigest_info['seo_category_id'] = seodigest_info.pop('seo_category')
    if seodigest_id is None:
        try:
            seodigest_obj = SeoDigest.objects.create(**seodigest_info)
        except IntegrityError:
            raise RPCIntegrityError
    else:
        try:
            seodigest_obj = SeoDigest.objects.get(id=seodigest_id)
            for k, v in seodigest_info.iteritems():
                setattr(seodigest_obj, k, v)
            seodigest_obj.save()
        except:
            info_logger.info(__import__('traceback').format_exc())
            raise RPCNotFoundException
    res['seodigest_id'] = seodigest_obj.id
    return res


@bind_context(uri_pre + '/listupdate')
def seodigest_listupdate(ctx, items):
    res = []
    for info in items:
        try:
            seodigest = SeoDigest.objects.get(pk=info['id'])
            seodigest.is_online = info['is_online']
            seodigest.save()
            res.append(seodigest.id)
        except Exception:
            logging_exception()
            continue

    return res


@bind_context(seo_pre + '/choices')
def seocategory_choices(ctx, q='', page=1, num=30, initial=None, group=None):
    page = int(page)
    num = int(num)

    query = choice_query(SeoCategory, ['id', 'name'], 'id', q, initial)
    # total_count = query.count()
    total_count = 0
    start_pos = (page - 1) * num
    start_pos = start_pos if start_pos >= 0 else 0
    results = [{
                   'id': u.id,
                   'text': u'{}:{}/{}'.format(u.id,
                                           u.name,CATEGORY_TYPE.getDesc(u.category_type)),
               } for u in query[start_pos: start_pos + num]]
    return {'total_count': total_count, 'results': results, 'page': page, 'num': num}


@bind_context(seo_pre + '/list')
def seocategory_list(ctx, options):
    dtobj = SeoCategoryDQ()
    return dtobj.process(**options)


@bind_context(seo_pre + '/listupdate')
def seocategory_listupdate(ctx, items):
    res = []
    for obj in items:
        try:
            seocategory = SeoCategory.objects.get(pk=obj['id'])
            seocategory.is_online = obj['is_online']
            seocategory.save()
            res.append(seocategory.id)
        except Exception:
            logging_exception()
            continue

    return res


@bind_context(seo_pre + '/get')
def seocategory_detail(ctx, seocategory_id, options=None):
    try:
        seocategory_info = SeoCategory.objects.get(id=seocategory_id)
    except:
        raise RPCNotFoundException
    if options is None:
        options = {
            'fields': None,
            'excludes': None,
            'expands': None,
        }
    data = to_dict(seocategory_info, **options)
    data['parent_categories'] = [parent_category.id for parent_category in seocategory_info.parent_categories(category_is_online=False)]
    data['child_categories'] = [child_category.id for child_category in seocategory_info.child_categories(category_is_online=False)]
    return data


@bind_context(seo_pre + '/modify')
@transaction.atomic
def seocategory_modify(ctx, seocategory_id=None, seocategory_info=None):
    res = {}
    parent_categories = seocategory_info.pop('parent_categories')
    child_categories =  seocategory_info.pop('child_categories')

    if seocategory_id is None:
        try:
            seocategory_obj = SeoCategory.objects.create(**seocategory_info)
        except IntegrityError:
            raise RPCIntegrityError
    else:
        try:
            seocategory_obj = SeoCategory.objects.get(id=seocategory_id)
            for k, v in seocategory_info.iteritems():
                setattr(seocategory_obj, k, v)
            seocategory_obj.save()
        except:
            info_logger.info(__import__('traceback').format_exc())
            raise RPCNotFoundException

    new_parent = set(SeoCategory.objects.filter(id__in=parent_categories))
    old_parent = set(seocategory_obj.parent_categories(category_is_online=False))
    for parent_obj in (new_parent - old_parent):
        CategoryRelation.objects.get_or_create(parent_category=parent_obj,child_category=seocategory_obj)
    CategoryRelation.objects.filter(child_category=seocategory_obj,parent_category__in=(
            old_parent - new_parent)).delete()

    res['id'] = seocategory_obj.id
    return res


@bind_context(fri_pre + '/list')
def friendlysite_list(ctx, options):
    dtobj = FriendlySiteDQ()
    return dtobj.process(**options)



@bind_context(fri_pre + '/get')
def friendlysite_detail(ctx, friendlysite_id, options=None):
    try:
        friendlysite_info = FriendlySite.objects.get(id=friendlysite_id)
    except:
        raise RPCNotFoundException
    if options is None:
        options = {
            'fields': None,
            'excludes': None,
            'expands': None,
        }
    data = to_dict(friendlysite_info, **options)
    return data


@bind_context(fri_pre + '/modify')
def friendlysite_edit(ctx, friendlysite_id=None, friendlysite_info=None):
    if friendlysite_info is None:
        return None

    city_id = friendlysite_info.pop("city")
    if city_id:
        try:
            friendlysite_info["city"] = City.objects.get(id=city_id)
        except:
            raise RPCNotFoundException

    friendlysite_new = model_edit(FriendlySite, friendlysite_id, friendlysite_info)

    return {'id': friendlysite_new.id}


@bind_context(fri_pre + '/listupdate')
def friendlysite_listupdate(ctx, items):
    res = []
    for obj in items:
        try:
            friendlysite = FriendlySite.objects.get(pk=obj['id'])
            friendlysite.is_online = obj['is_online']
            friendlysite.site_name = obj['site_name']
            friendlysite.site_url = obj['site_url']
            friendlysite.city_id = obj['city_id']
            friendlysite.save()
            res.append(friendlysite.id)
        except Exception:
            logging_exception()
            continue

    return res


@bind_context(inn_pre + '/list')
def innerhyperlink_list(ctx, options):
    dtobj = InnerHyperlinkDQ()
    return dtobj.process(**options)


@bind_context(inn_pre + '/get')
def innerhyperlink_detail(ctx, innerhyperlink_id, options=None):
    try:
        innerhyperlink_info = InnerHyperlink.objects.get(id=innerhyperlink_id)
    except:
        raise RPCNotFoundException
    if options is None:
        options = {
            'fields': None,
            'excludes': None,
            'expands': None,
        }
    data = to_dict(innerhyperlink_info, **options)
    return data


@bind_context(inn_pre + '/modify')
def innerhyperlink_edit(ctx, innerhyperlink_id=None, innerhyperlink_info=None):
    if innerhyperlink_info is None:
        return None
    innerhyperlink_new = model_edit(InnerHyperlink, innerhyperlink_id, innerhyperlink_info)

    return {'id': innerhyperlink_new.id}


@bind_context(inn_pre + '/listupdate')
def innerhyperlink_listupdate(ctx, items):
    res = []
    for obj in items:
        try:
            innerhyperlink = InnerHyperlink.objects.get(pk=obj['id'])
            innerhyperlink.name = obj['name']
            innerhyperlink.url = obj['url']
            innerhyperlink.save()
            res.append(innerhyperlink.id)
        except Exception:
            logging_exception()
            continue

    return res

