# -*- coding: UTF-8 -*-
import functools
import hashlib
import json

import six
from django.conf import settings
from django.db.models import Model

from talos.cache.base import page_cache


class ListInterfaceDescriptor(object):
    instance_list = []

    def __init__(self, func, offset_name, limit_name, element_model, element_func_list):
        assert isinstance(offset_name, six.string_types + (type(None),))
        assert isinstance(limit_name, six.string_types)
        if element_model is not None:
            assert isinstance(element_model, type)
            assert issubclass(element_model, Model)
        if element_func_list is None:
            element_func_list = []
        for ef in element_func_list:
            assert any([
                callable(ef),
                isinstance(ef, property),
            ])

        self.func = func
        self.offset_name = offset_name
        self.limit_name = limit_name
        self.element_model = element_model
        self.element_func_list = element_func_list

        self.instance_list.append(self)

    @classmethod
    def decorator(cls, offset_name=None, limit_name=None, element_model=None, element_func_list=None):

        def inner_decorator(func):
            @functools.wraps(func)
            def wrapper(*args, **kwargs):
                limit = kwargs.get(limit_name, 0)
                if limit > settings.COUNT_LIMIT:
                    kwargs[limit_name] = settings.COUNT_LIMIT
                return func(*args, **kwargs)

            descriptor = cls(
                func=wrapper,
                offset_name=offset_name,
                limit_name=limit_name,
                element_model=element_model,
                element_func_list=element_func_list,
            )
            wrapper.list_interface_descriptor = descriptor

            return wrapper

        return inner_decorator

    @classmethod
    def get_descriptor_from_decorated_func(cls, func):
        return


list_interface = ListInterfaceDescriptor.decorator


def cache_page(timeout):
    def wrap(f):
        # bind_context和cache_page装饰器一起使用,由于ctx参数问题会报错
        @functools.wraps(f)
        def decorated(**kwargs):
            method_url = "%s.%s?%s" % (f.__module__, f.__name__, json.dumps(kwargs, sort_keys=True))
            method_md5 = hashlib.md5(method_url.encode()).hexdigest()
            cache_key = "cache:%s:rpc:%s" % (method_md5, settings.VERSION)
            data = page_cache.get(cache_key)
            try:
                if data:
                    resp = json.loads(data)
                    return resp
            except:
                pass
            obj = f(**kwargs)
            page_cache.setex(cache_key, timeout, json.dumps(obj))
            return obj

        return decorated

    return wrap


def listing(arg_limit='count'):
    def wrapper(f):
        @functools.wraps(f)
        def inner(*args, **kwargs):
            limit = kwargs.get(arg_limit, 0)
            if limit:
                kwargs[arg_limit] = settings.COUNT_LIMIT if limit > settings.COUNT_LIMIT else limit
            return f(*args, **kwargs)
        return inner
    return wrapper