package share

import (
	"context"
	"fmt"
	"regexp"
	"strings"
	"time"

	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/os/gcache"
	"github.com/gogf/gf/v2/util/gconv"
)

var ShareManager = newSessionManager()
var (
	// ErrCacheMiss 表示缓存未命中
	ErrCacheMiss = gerror.New("缓存未找到")
	// ErrTypeConvert 表示类型转换失败
	ErrTypeConvert = gerror.New("缓存值类型转换失败")
)

// cacheStore 泛型缓存存储
type cacheStore[T any] struct {
	manager *gcache.Cache // 缓存管理器
	prefix  string        // 缓存键前缀
}

// 生成带前缀的缓存键
func (s *cacheStore[T]) formatKey(key string) string {
	return s.prefix + strings.TrimSpace(key)
}

// Get 通过键获取缓存值
func (s *cacheStore[T]) Get(ctx context.Context, key string) (T, error) {
	var zero T
	result, err := s.manager.Get(ctx, s.formatKey(key))
	if err != nil {
		return zero, gerror.Wrapf(err, "获取缓存失败，键: %s", key)
	}
	if result.IsEmpty() {
		return zero, ErrCacheMiss
	}

	// 使用 ConvertWithRefer 进行类型转换
	value := gconv.ConvertWithRefer(result.Val(), zero)

	// 类型断言检查转换结果
	converted, ok := value.(T)
	if !ok {
		return zero, gerror.Wrapf(
			ErrTypeConvert,
			"键: %s，缓存值实际类型: %T，期望类型: %T",
			key, result.Val(), zero,
		)
	}

	return converted, nil
}

// Set 设置缓存值并带有效期
func (s *cacheStore[T]) Set(ctx context.Context, key string, value T, duration time.Duration) error {
	err := s.manager.Set(ctx, s.formatKey(key), value, duration)
	if err != nil {
		return gerror.Wrapf(err, "设置缓存失败，键: %s，值: %v", key, value)
	}
	fmt.Printf("[INFO] 缓存操作 [%s] 键: %s 值: %v 有效期: %v\n",
		s.prefix, key, value, duration)
	return nil
}

// Del 删除缓存
func (s *cacheStore[T]) Del(ctx context.Context, key string) error {
	_, err := s.manager.Remove(ctx, s.formatKey(key))
	if err != nil {
		return gerror.Wrapf(err, "删除缓存失败，键: %s", key)
	}
	fmt.Printf("[INFO] 删除缓存 [%s] 键: %s 成功\n", s.prefix, key)
	return nil
}

// Contains 检查缓存是否存在
func (s *cacheStore[T]) Contains(ctx context.Context, key string) (bool, error) {
	exists, err := s.manager.Contains(ctx, s.formatKey(key))
	if err != nil {
		return false, gerror.Wrapf(err, "检查缓存是否存在失败，键: %s", key)
	}
	return exists, nil
}

// GetOrSet 获取缓存值，如果不存在则设置默认值
func (s *cacheStore[T]) GetOrSet(ctx context.Context, key string, defaultValue T, duration time.Duration) (T, error) {
	var zero T
	result, err := s.manager.GetOrSet(ctx, s.formatKey(key), defaultValue, duration)
	if err != nil {
		return zero, gerror.Wrapf(err, "获取或设置缓存失败，键: %s", key)
	}

	// 类型转换
	value := gconv.ConvertWithRefer(result.Val(), zero)
	converted, ok := value.(T)
	if !ok {
		return zero, gerror.Wrapf(
			ErrTypeConvert,
			"键: %s，缓存值实际类型: %T，期望类型: %T",
			key, result.Val(), zero,
		)
	}

	return converted, nil
}

// Scan 扫描匹配模式的键（先获取所有键，再内存筛选）
func (s *cacheStore[T]) Scan(ctx context.Context, pattern string) ([]string, error) {
	// 1. 获取所有键
	allKeys, err := s.manager.Keys(ctx)
	if err != nil {
		return nil, gerror.Wrapf(err, "获取所有键失败")
	}

	// 2. 筛选符合模式的键（使用字符串匹配，支持简单通配符*）
	var matchedKeys []string
	for _, key := range allKeys {
		// 简单模式匹配：支持*匹配任意字符（可根据需求扩展为glob匹配）
		if matchSimplePattern(key.(string), pattern) {
			matchedKeys = append(matchedKeys, key.(string))
		}
	}
	return matchedKeys, nil
}

// 简单模式匹配（支持*通配符）
func matchSimplePattern(str, pattern string) bool {
	// 替换pattern中的*为正则匹配符，转义其他特殊字符
	regexPattern := strings.ReplaceAll(regexp.QuoteMeta(pattern), "\\*", ".*")
	regexPattern = "^" + regexPattern + "$" // 全匹配
	matched, _ := regexp.MatchString(regexPattern, str)
	return matched
}

// MGet 批量获取多个键的值（循环调用Get实现）
func (s *cacheStore[T]) MGet(ctx context.Context, keys []string) ([]interface{}, error) {
	values := make([]interface{}, len(keys))
	for i, key := range keys {
		formattedKey := s.formatKey(key) // 格式化键（添加前缀）
		result, err := s.manager.Get(ctx, formattedKey)
		if err != nil {
			return nil, gerror.Wrapf(err, "批量获取缓存失败，键: %s", key)
		}
		if result.IsEmpty() {
			values[i] = nil // 未命中时存nil
		} else {
			values[i] = result.Val()
		}
	}
	return values, nil
}
