# (c) cavaliba.com - home - cache.py

import copy
import os

from django.conf import settings
from django.core.cache import cache as django_cache

# cookie/session : per user ; logout to clear ; aaa
# localmem       : per request
# localmem       : per multiple request
# django (redis) : timeout per cache

# -----------------------------------------
# GENERIC CAVALIBA CACHE
# -----------------------------------------


class DataCache:
    def __init__(self, cachename=None, timeout=10):

        self.cachename = cachename
        self.localmem = {}

        self.timeout = timeout  # django cache default timeout

        self.tenant = os.environ.get("CAVALIBA_TENANT", default="cavaliba")
        self.prefix = f"{self.tenant}::cache::{self.cachename}"

    def get(self, key=None):

        if not key:
            return

        # add tenant/cache prefix
        fullkeyname = f"{self.prefix}::{key}"

        # 1. search in-memory cache
        if fullkeyname in self.localmem:
            return copy.deepcopy(self.localmem[fullkeyname])

        # 2. django Cache (redis, memcache, ...)
        a = django_cache.get(fullkeyname)
        if a:
            self.localmem[fullkeyname] = copy.deepcopy(a)
            return a

    def set(self, key=None, value=None):

        if not key:
            return

        # add tenant/cache prefix
        fullkeyname = f"{self.prefix}::{key}"

        try:
            self.localmem[fullkeyname] = copy.deepcopy(value)
        except Exception:
            pass

        try:
            django_cache.set(fullkeyname, value, self.timeout)
        except Exception:
            pass

    def delete(self, key):

        if not key:
            return

        # add tenant/cache prefix
        fullkeyname = f"{self.prefix}::{key}"

        self.localmem.pop(fullkeyname, None)
        django_cache.delete(fullkeyname)

    def clear(self):

        self.localmem = {}
        try:
            django_cache.delete_many(django_cache.keys(f"{self.prefix}::*"))
        except AttributeError:
            # LocMemCache has no .keys() — clear the entire cache
            django_cache.clear()

    def delete_by_prefix(self, subprefix):
        """Delete all entries whose key starts with subprefix (e.g. classname)."""

        full_subprefix = f"{self.prefix}::{subprefix}"

        # localmem: remove matching keys
        to_delete = [k for k in self.localmem if k.startswith(full_subprefix)]
        for k in to_delete:
            del self.localmem[k]

        # django cache (redis): delete matching keys
        try:
            matching = django_cache.keys(f"{full_subprefix}::*")
            if matching:
                django_cache.delete_many(matching)
        except AttributeError:
            pass


# -----------------------------------------
# caches
# -----------------------------------------

# per hit only / in-memory / per gunicorn worker
cache_aaa = {}

# Configuration
cache_configuration = {}
cache2_configuration = DataCache(
    cachename="cache2_configuration", timeout=settings.CAVALIBA_CACHE_CONFIGURATION_TIMEOUT
)


# Schema()
cache2_schema = DataCache(cachename="cache2_schema", timeout=settings.CAVALIBA_CACHE_SCHEMA_TIMEOUT)

# Instance()
cache2_instance = DataCache(
    cachename="cache2_instance", timeout=settings.CAVALIBA_CACHE_INSTANCE_TIMEOUT
)

# data content of enumerate object
cache2_enumerate = DataCache(
    cachename="cache2_enumerate", timeout=settings.CAVALIBA_CACHE_ENUMERATE_TIMEOUT
)

# dict datapoint
cache2_datapoint = DataCache(
    cachename="cache2_datapoint", timeout=settings.CAVALIBA_CACHE_DATAPOINT_TIMEOUT
)


def clear():
    """empty all caches"""

    # TODO
    global cache_configuration
    cache_configuration = {}

    global cache_aaa
    cache_aaa = {}

    global cache2_schema
    cache2_schema.clear()

    global cache2_configuration
    cache2_configuration.clear()

    global cache2_instance
    cache2_instance.clear()

    global cache2_enumerate  # preprocessed enum data structure
    cache2_enumerate.clear()

    global cache2_datapoint
    cache2_datapoint.clear()


# Per HIT / REQUEST cache reset
def init():
    """empty per-request cache"""

    # TODO
    global cache_configuration
    cache_configuration = {}

    # new

    global cache_aaa
    cache_aaa = {}

    global cache2_schema
    cache2_schema.localmem = {}

    global cache2_configuration
    cache2_configuration.localmem = {}

    global cache2_instance
    cache2_instance.localmem = {}

    global cache2_enumerate
    cache2_enumerate.localmem = {}

    global cache2_datapoint
    cache2_datapoint.localmem = {}
