from functools import wraps
import time
from flask import current_app
import logging
from sqlalchemy.exc import SQLAlchemyError
from scripts.models import db
from collections import defaultdict

# 简单的内存缓存实现
class QueryCache:
    def __init__(self, max_size=100, ttl=300):  # 默认缓存300秒
        self.cache = {}
        self.max_size = max_size
        self.ttl = ttl
        self.access_times = defaultdict(int)

    def get(self, key):
        if key in self.cache:
            item = self.cache[key]
            if time.time() - item['time'] < self.ttl:
                self.access_times[key] += 1
                return item['value']
            else:
                # 缓存过期，删除
                del self.cache[key]
                if key in self.access_times:
                    del self.access_times[key]
        return None

    def set(self, key, value):
        # 如果缓存满了，删除最少访问的项
        if len(self.cache) >= self.max_size:
            # 找出访问次数最少的键
            if self.access_times:
                min_key = min(self.access_times, key=self.access_times.get)
                if min_key in self.cache:
                    del self.cache[min_key]
                del self.access_times[min_key]

        self.cache[key] = {
            'value': value,
            'time': time.time()
        }
        self.access_times[key] = 1
        return value

# 创建全局缓存实例
query_cache = QueryCache()

# 数据库操作装饰器 - 用于缓存结果
def cache_query(ttl=300):
    """
    缓存查询结果的装饰器
    :param ttl: 缓存有效期（秒）
    """
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            # 生成缓存键
            cache_key = f"{func.__name__}:{str(args)}:{str(kwargs)}"
            
            # 尝试从缓存获取
            cached_result = query_cache.get(cache_key)
            if cached_result is not None:
                return cached_result
            
            # 执行查询
            result = func(*args, **kwargs)
            
            # 设置缓存
            query_cache.set(cache_key, result)
            return result
        return wrapper
    return decorator

# 数据库操作装饰器 - 用于异常处理
def db_operation(retries=3, retry_delay=0.5):
    """
    数据库操作的装饰器，提供异常处理和重试功能
    :param retries: 重试次数
    :param retry_delay: 重试延迟(秒)
    """
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            last_error = None
            for attempt in range(retries):
                try:
                    return func(*args, **kwargs)
                except SQLAlchemyError as e:
                    last_error = e
                    current_app.logger.warning(f"数据库操作失败: {str(e)}，尝试重试 ({attempt+1}/{retries})")
                    
                    # 回滚会话
                    db.session.rollback()
                    
                    # 如果不是最后一次尝试，则等待后重试
                    if attempt < retries - 1:
                        time.sleep(retry_delay)
            
            # 所有重试都失败
            current_app.logger.error(f"数据库操作失败(已重试{retries}次): {str(last_error)}")
            raise last_error
        return wrapper
    return decorator

# 辅助函数：清除特定表相关的所有缓存
def clear_table_cache(table_name):
    """
    清除与特定表相关的所有缓存
    :param table_name: 表名
    """
    keys_to_delete = []
    for key in list(query_cache.cache.keys()):
        if table_name.lower() in key.lower():
            keys_to_delete.append(key)
    
    for key in keys_to_delete:
        if key in query_cache.cache:
            del query_cache.cache[key]
        if key in query_cache.access_times:
            del query_cache.access_times[key]

# 通用查询函数，包含异常处理和缓存
@db_operation()
@cache_query()
def get_all_distinct_values(model, column_name):
    """
    获取指定模型指定列的所有不同值
    :param model: 模型类
    :param column_name: 列名
    :return: 所有不同值的列表
    """
    column = getattr(model, column_name)
    results = db.session.query(column).distinct().all()
    return [result[0] for result in results if result[0]] 