import time
import logging
from django.core.cache import CacheHandler
from django.utils import timezone
from .context import TrackerContext
from .models import OperationLog
from .queue import enqueue_log
import datetime

logger = logging.getLogger(__name__)

class CacheWrapper:
    def __init__(self, cache, alias):
        self._cache = cache
        self._alias = alias
        self._is_wrapped_by_ops_logger = True

    def __getattr__(self, name):
        return getattr(self._cache, name)

    def get(self, key, default=None, version=None):
        start = time.time()
        try:
            value = self._cache.get(key, default, version)
            hit = value is not default
            return value
        finally:
            self._log_op('get', key, start, hit=hit)

    def set(self, key, value, timeout=None, version=None):
        start = time.time()
        try:
            return self._cache.set(key, value, timeout, version)
        finally:
            self._log_op('set', key, start)

    def delete(self, key, version=None):
        start = time.time()
        try:
            return self._cache.delete(key, version)
        finally:
            self._log_op('delete', key, start)
            
    def _log_op(self, operation, key, start_time_float, hit=None):
        trace_id = TrackerContext.get_trace_id()
        if not trace_id:
            return

        end_time = time.time()
        duration = (end_time - start_time_float) * 1000
        
        details = {
            'key': key,
            'alias': self._alias,
            'hit': hit
        }

        enqueue_log(
            trace_id=trace_id,
            operation_type=OperationLog.OpType.CACHE,
            level='DEBUG',
            start_time=timezone.now() - datetime.timedelta(milliseconds=duration),
            end_time=timezone.now(),
            duration=duration,
            user_id=TrackerContext.get_user_id(),
            username=TrackerContext.get_username(),
            details=details,
        )

def install_cache_logger():
    """
    Patch CacheHandler to return wrapped caches.
    """
    original_getitem = CacheHandler.__getitem__

    def logging_getitem(self, alias):
        cache = original_getitem(self, alias)
        if getattr(cache, '_is_wrapped_by_ops_logger', False) or isinstance(cache, CacheWrapper):
            return cache
        
        return CacheWrapper(cache, alias)

    CacheHandler.__getitem__ = logging_getitem
