package cache

import (
	"context"
	"time"
)

// CacheManager 缓存管理器
type CacheManager struct {
	l1 *L1Cache
	l2 L2Cache
}

// NewCacheManager 创建缓存管理器
func NewCacheManager(l1 *L1Cache, l2 L2Cache) *CacheManager {
	return &CacheManager{
		l1: l1,
		l2: l2,
	}
}

// Get 获取缓存（先从L1获取，再从L2获取）
func (cm *CacheManager) Get(ctx context.Context, key string) (interface{}, bool) {
	// 先从L1缓存获取
	if value, ok := cm.l1.Get(key); ok {
		return value, true
	}

	// 再从L2缓存获取
	if cm.l2 != nil {
		if value, err := cm.l2.Get(ctx, key); err == nil && value != nil {
			// 回写L1缓存
			cm.l1.Set(key, value, 5*time.Minute)
			return value, true
		}
	}

	return nil, false
}

// Set 设置缓存（同时写入L1和L2）
func (cm *CacheManager) Set(ctx context.Context, key string, value interface{}, l1TTL, l2TTL time.Duration) error {
	// 写入L1缓存
	cm.l1.Set(key, value, l1TTL)

	// 写入L2缓存
	if cm.l2 != nil {
		if err := cm.l2.Set(ctx, key, value, l2TTL); err != nil {
			// L2写入失败不影响整体流程
			return err
		}
	}

	return nil
}

// Delete 删除缓存（同时删除L1和L2）
func (cm *CacheManager) Delete(ctx context.Context, key string) error {
	// 删除L1缓存
	cm.l1.Delete(key)

	// 删除L2缓存
	if cm.l2 != nil {
		return cm.l2.Delete(ctx, key)
	}

	return nil
}

// Exists 检查缓存是否存在
func (cm *CacheManager) Exists(ctx context.Context, key string) bool {
	// 先检查L1
	if _, ok := cm.l1.Get(key); ok {
		return true
	}

	// 再检查L2
	if cm.l2 != nil {
		if exists, err := cm.l2.Exists(ctx, key); err == nil && exists {
			return true
		}
	}

	return false
}

// Clear 清空缓存
func (cm *CacheManager) Clear(ctx context.Context) error {
	// 清空L1缓存
	cm.l1.Clear()

	// 清空L2缓存
	if cm.l2 != nil {
		return cm.l2.Clear(ctx)
	}

	return nil
}

// GetL1 获取L1缓存
func (cm *CacheManager) GetL1() *L1Cache {
	return cm.l1
}

// GetL2 获取L2缓存
func (cm *CacheManager) GetL2() L2Cache {
	return cm.l2
}

// Increment 原子递增（同时更新L1和L2）
func (cm *CacheManager) Increment(ctx context.Context, key string, delta int64, ttl time.Duration) (int64, error) {
	// 先更新L1
	cm.l1.Increment(key, delta, ttl)

	// 再更新L2
	if cm.l2 != nil {
		return cm.l2.Increment(ctx, key, delta, ttl)
	}

	return cm.l1.Increment(key, 0, 0), nil
}
