// Package systemconfig 实现受控系统配置注册、缓存和持久化 Adapter。
package systemconfig

import (
	"context"
	stderrors "errors"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/bytedance/sonic"
	"github.com/redis/go-redis/v9"

	"github.com/break/junhong_cmp_fiber/pkg/constants"
)

// Definition 是业务模块拥有的配置 Key 注册定义。
type Definition struct {
	Key          string
	Module       string
	ValueType    string
	DefaultValue string
	Description  string
	Readonly     bool
	Sensitive    bool
	Control      string
	EnumValues   []string
	Min          *int64
	Max          *int64
	Validator    func(string) error
}

// Registry 保存可写配置的代码权威定义。
type Registry struct {
	mu            sync.RWMutex
	definitions   map[string]Definition
	lastValidated map[string]string
}

// NewRegistry 创建空注册表；具体业务 Key 由所属模块注册。
func NewRegistry() *Registry {
	return &Registry{definitions: map[string]Definition{}, lastValidated: map[string]string{}}
}

// Register 注册一个业务模块拥有的配置 Key。
func (r *Registry) Register(definition Definition) error {
	if !validKey(definition.Key) || strings.TrimSpace(definition.Module) == "" || strings.TrimSpace(definition.Description) == "" {
		return stderrors.New("系统配置注册信息不完整")
	}
	if err := ValidateValue(definition, definition.DefaultValue); err != nil {
		return err
	}
	r.mu.Lock()
	defer r.mu.Unlock()
	if existing, exists := r.definitions[definition.Key]; exists {
		if existing.ValueType != definition.ValueType {
			return stderrors.New("系统配置 Key 存在类型冲突")
		}
		return stderrors.New("系统配置 Key 重复注册")
	}
	r.definitions[definition.Key] = definition
	r.lastValidated[definition.Key] = definition.DefaultValue
	return nil
}

// Get 查询已注册定义。
func (r *Registry) Get(key string) (Definition, bool) {
	r.mu.RLock()
	defer r.mu.RUnlock()
	definition, exists := r.definitions[key]
	return definition, exists
}

// List 返回注册定义快照。
func (r *Registry) List() []Definition {
	r.mu.RLock()
	defer r.mu.RUnlock()
	items := make([]Definition, 0, len(r.definitions))
	for _, definition := range r.definitions {
		items = append(items, definition)
	}
	return items
}

// Remember 保存最近一次通过注册校验的值。
func (r *Registry) Remember(key, value string) {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.lastValidated[key] = value
}

// LastValidatedOrDefault 返回最近验证值或代码安全默认值。
func (r *Registry) LastValidatedOrDefault(definition Definition) string {
	r.mu.RLock()
	defer r.mu.RUnlock()
	if value, exists := r.lastValidated[definition.Key]; exists {
		return value
	}
	return definition.DefaultValue
}

// ValidateValue 按注册类型、枚举和值域校验字符串化配置值。
func ValidateValue(definition Definition, value string) error {
	switch definition.ValueType {
	case constants.SystemConfigTypeString:
	case constants.SystemConfigTypeInt:
		parsed, err := strconv.ParseInt(value, 10, 64)
		if err != nil {
			return stderrors.New("系统配置值必须是整数")
		}
		if definition.Min != nil && parsed < *definition.Min {
			return stderrors.New("系统配置值小于允许范围")
		}
		if definition.Max != nil && parsed > *definition.Max {
			return stderrors.New("系统配置值大于允许范围")
		}
	case constants.SystemConfigTypeBool:
		if value != "true" && value != "false" {
			return stderrors.New("系统配置值必须是 true 或 false")
		}
	case constants.SystemConfigTypeJSON:
		var parsed any
		if sonic.Unmarshal([]byte(value), &parsed) != nil {
			return stderrors.New("系统配置值必须是合法 JSON")
		}
	default:
		return stderrors.New("系统配置类型不受支持")
	}
	if len(definition.EnumValues) > 0 {
		matched := false
		for _, allowed := range definition.EnumValues {
			if value == allowed {
				matched = true
				break
			}
		}
		if !matched {
			return stderrors.New("系统配置值不在允许枚举中")
		}
	}
	if definition.Validator != nil {
		return definition.Validator(value)
	}
	return nil
}

func validKey(key string) bool {
	parts := strings.Split(key, ".")
	if len(parts) < 3 {
		return false
	}
	for _, part := range parts {
		if strings.TrimSpace(part) == "" {
			return false
		}
	}
	return true
}

// Cache 是系统配置使用的最小缓存边界。
type Cache interface {
	Get(ctx context.Context, key string) (string, error)
	Set(ctx context.Context, key, value string, ttl time.Duration) error
	Delete(ctx context.Context, key string) error
}

// RedisCache 使用 Redis 实现系统配置短期缓存。
type RedisCache struct {
	client *redis.Client
}

// NewRedisCache 创建系统配置 Redis Adapter。
func NewRedisCache(client *redis.Client) *RedisCache {
	return &RedisCache{client: client}
}

// Get 读取缓存值。
func (c *RedisCache) Get(ctx context.Context, key string) (string, error) {
	return c.client.Get(ctx, key).Result()
}

// Set 回填缓存值。
func (c *RedisCache) Set(ctx context.Context, key, value string, ttl time.Duration) error {
	return c.client.Set(ctx, key, value, ttl).Err()
}

// Delete 失效单 Key 缓存。
func (c *RedisCache) Delete(ctx context.Context, key string) error {
	return c.client.Del(ctx, key).Err()
}
