# -*- coding: utf-8 -*-
from .clients import CacheClient
import logging
from functools import wraps
import time


def log_time(func):
    """
    used for debugging
    :param func:
    :return:
    """
    def wrapped(*args, **kwargs):
        start = time.time()
        res = func(*args, **kwargs)
        logging.error('TIMER {}: {}'.format(func.__name__, time.time() - start))
        return res

    return wrapped


def cached(key, bypass=False, expire=2592000, fmt='json'):  # a month
    """
    Запомниает результат функции во внешнем кэше.
    Looks for func result in memcache
    Sets result if none found in memcache
    :param key: string
    :param bypass: don't use memcache
    :param expire: seconds till cache expires
    :param fmt: str: json or yaml
    :return: func
    """

    def wrapper(func):
        if bypass:
            return func

        @wraps(func)
        def wrapped(*args, **kwargs):
            cache = CacheClient(expire=expire, fmt=fmt)
            value = cache.get(key)
            if value:
                return value
            else:
                result = func(*args, **kwargs)
                cache.set(key, result)
                return result

        return wrapped

    return wrapper


class memoized_property(object):
    """
    Дискриптор, который используется как декоратор для методов класса,
    добавляет инстансу одноименный атрибут и
    сохраняет в нем значение вычисления метода
    """
    def __init__(self, method):
        self._method = method

    def __get__(self, instance, owner):
        if instance is None:
            return None
        value = self._method(instance)
        setattr(instance, self._method.__name__, value)
        return value


def cache_lock(func):
    """
    Grabs lock for specified function,
    So that other processes on this server won't be able to call it
    TODO: cross server lock
    :param func:
    """

    def wrapper(*args, **kwargs):
        cache = CacheClient()
        cache_key = 'lock_{}'.format(func.__name__)
        if not cache.get(cache_key):
            cache.set(cache_key, True)
            try:
                result = func(*args, **kwargs)
            finally:
                cache.delete(cache_key)
            return result

    return wrapper
