# (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)

#  DB SireneUser objects
cache2_iam_user = DataCache(cachename="cache2_iam_user", timeout=settings.CAVALIBA_CACHE_IAM_USER_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()

    global cache2_iam_user
    cache2_iam_user.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 = {}

    global cache2_iam_user
    cache2_iam_user.localmem = {}
