import time
import functools
import threading
from typing import Any, Callable, Dict, Tuple

CacheKey = Tuple[Any, ...]


class _CacheStore:
    def __init__(self):
        self.store: Dict[CacheKey, Tuple[float, Any]] = {}
        self.lock = threading.Lock()


GLOBAL_CACHE = _CacheStore()


def _make_key(args: tuple, kwargs: dict) -> CacheKey:
    if kwargs:
        return args + tuple(sorted(kwargs.items()))
    return args


def cachetiny(ttl: int = 60, log: bool = False) -> Callable:
    """
    Simple in-memory TTL cache decorator.

    Args:
        ttl (int): Cache expiration in seconds
        log (bool): Print when retrieving cache or computing value
    """

    def decorator(func: Callable) -> Callable:

        @functools.wraps(func)
        def wrapper(*args, **kwargs):

            key = (func.__module__, func.__name__) + _make_key(args, kwargs)
            now = time.time()

            with GLOBAL_CACHE.lock:
                if key in GLOBAL_CACHE.store:
                    expiry, value = GLOBAL_CACHE.store[key]

                    if now < expiry:
                        if log:
                            print(
                                f"[simplecache] USING CACHE -> {func.__name__}{args}{kwargs}"
                            )
                        return value

                    del GLOBAL_CACHE.store[key]

            if log:
                print(f"[simplecache] COMPUTING -> {func.__name__}{args}{kwargs}")

            result = func(*args, **kwargs)

            with GLOBAL_CACHE.lock:
                GLOBAL_CACHE.store[key] = (now + ttl, result)

            return result

        return wrapper

    return decorator
