package systemconfig

import (
	"context"
	stderrors "errors"
	"sort"

	"github.com/redis/go-redis/v9"
	"go.uber.org/zap"
	"gorm.io/gorm"

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

// AlertSink 接收配置读取和缓存故障的中文安全告警。
type AlertSink interface {
	Warn(ctx context.Context, code, component, safeID, summary string)
}

// LogAlertSink 使用应用日志承接安全告警。
type LogAlertSink struct {
	logger *zap.Logger
}

// NewLogAlertSink 创建系统配置日志告警 Adapter。
func NewLogAlertSink(logger *zap.Logger) *LogAlertSink {
	if logger == nil {
		logger = zap.NewNop()
	}
	return &LogAlertSink{logger: logger}
}

// Warn 记录不包含配置值的中文安全告警。
func (s *LogAlertSink) Warn(_ context.Context, code, component, safeID, summary string) {
	s.logger.Warn(summary, zap.String("error_code", code), zap.String("component", component), zap.String("safe_id", safeID))
}

// Reader 提供以 PostgreSQL 为唯一事实来源的缓存读取能力。
type Reader struct {
	db       *gorm.DB
	registry *Registry
	cache    Cache
	alerts   AlertSink
}

func (r *Reader) warn(ctx context.Context, code, key, summary string) {
	if r.alerts != nil {
		r.alerts.Warn(ctx, code, "system_config", key, summary)
	}
}

// NewReader 创建系统配置读取器。
func NewReader(db *gorm.DB, registry *Registry, cache Cache, alerts AlertSink) *Reader {
	return &Reader{db: db, registry: registry, cache: cache, alerts: alerts}
}

// Get 读取单个已注册配置；Redis 故障时回退 PostgreSQL。
func (r *Reader) Get(ctx context.Context, key string) (string, error) {
	definition, registered := r.registry.Get(key)
	if !registered {
		return "", stderrors.New("系统配置 Key 未注册")
	}
	cacheKey := constants.RedisSystemConfigKey(key)
	if r.cache != nil {
		if value, err := r.cache.Get(ctx, cacheKey); err == nil {
			if ValidateValue(definition, value) == nil {
				r.registry.Remember(key, value)
				return value, nil
			}
			r.warn(ctx, "SYSTEM_CONFIG_CACHE_INVALID", key, "系统配置缓存值非法，已回退 PostgreSQL")
		} else if err != redis.Nil {
			r.warn(ctx, "SYSTEM_CONFIG_CACHE_READ_FAILED", key, "系统配置缓存读取失败，已回退 PostgreSQL")
		}
	}
	var record model.SystemConfig
	err := r.db.WithContext(ctx).Where("config_key = ?", key).First(&record).Error
	if err == gorm.ErrRecordNotFound {
		return definition.DefaultValue, nil
	}
	if err != nil {
		return "", err
	}
	value := record.ConfigValue
	if ValidateValue(definition, value) != nil {
		value = r.registry.LastValidatedOrDefault(definition)
		r.warn(ctx, "SYSTEM_CONFIG_DATABASE_VALUE_INVALID", key, "数据库配置值非法，已使用最近验证值或安全默认值")
	} else {
		r.registry.Remember(key, value)
	}
	if r.cache != nil {
		if err := r.cache.Set(ctx, cacheKey, value, constants.SystemConfigCacheTTL); err != nil {
			r.warn(ctx, "SYSTEM_CONFIG_CACHE_WRITE_FAILED", key, "系统配置缓存回填失败")
		}
	}
	return value, nil
}

// GetStrict 严格读取单个已注册配置；已落库的非法值或数据库读取失败不会回退默认值。
// 该入口用于支付方式等必须失败关闭的关键配置，未落库时仍返回代码注册的首次初始化默认值。
func (r *Reader) GetStrict(ctx context.Context, key string) (string, error) {
	definition, registered := r.registry.Get(key)
	if !registered {
		return "", stderrors.New("系统配置 Key 未注册")
	}
	cacheKey := constants.RedisSystemConfigKey(key)
	if r.cache != nil {
		if value, err := r.cache.Get(ctx, cacheKey); err == nil {
			if ValidateValue(definition, value) == nil {
				return value, nil
			}
			r.warn(ctx, "SYSTEM_CONFIG_CACHE_INVALID", key, "关键系统配置缓存值非法，已回源 PostgreSQL")
		} else if err != redis.Nil {
			r.warn(ctx, "SYSTEM_CONFIG_CACHE_READ_FAILED", key, "关键系统配置缓存读取失败，已回源 PostgreSQL")
		}
	}
	var record model.SystemConfig
	err := r.db.WithContext(ctx).Where("config_key = ?", key).First(&record).Error
	if err == gorm.ErrRecordNotFound {
		return definition.DefaultValue, nil
	}
	if err != nil {
		return "", err
	}
	if ValidateValue(definition, record.ConfigValue) != nil {
		r.warn(ctx, "SYSTEM_CONFIG_DATABASE_VALUE_INVALID", key, "关键系统配置数据库值非法，已失败关闭")
		return "", stderrors.New("系统配置数据库值非法")
	}
	if r.cache != nil {
		if err := r.cache.Set(ctx, cacheKey, record.ConfigValue, constants.SystemConfigCacheTTL); err != nil {
			r.warn(ctx, "SYSTEM_CONFIG_CACHE_WRITE_FAILED", key, "关键系统配置缓存回填失败")
		}
	}
	return record.ConfigValue, nil
}

// ListItem 是查询层组装 DTO 所需的稳定投影。
type ListItem struct {
	Definition Definition
	Record     *model.SystemConfig
	Value      string
	Registered bool
}

// List 合并代码注册表和数据库遗留记录；未注册记录强制只读。
func (r *Reader) List(ctx context.Context, module string) ([]ListItem, error) {
	var records []model.SystemConfig
	query := r.db.WithContext(ctx).Order("config_key ASC")
	if module != "" {
		query = query.Where("module = ?", module)
	}
	if err := query.Find(&records).Error; err != nil {
		return nil, err
	}
	byKey := make(map[string]*model.SystemConfig, len(records))
	for index := range records {
		byKey[records[index].ConfigKey] = &records[index]
	}
	items := make([]ListItem, 0, len(records)+len(r.registry.List()))
	for _, definition := range r.registry.List() {
		if module != "" && definition.Module != module {
			continue
		}
		record := byKey[definition.Key]
		value := definition.DefaultValue
		if record != nil {
			value = record.ConfigValue
			if ValidateValue(definition, value) != nil {
				value = r.registry.LastValidatedOrDefault(definition)
				r.warn(ctx, "SYSTEM_CONFIG_DATABASE_VALUE_INVALID", definition.Key, "数据库配置值非法，列表已使用安全值")
			} else {
				r.registry.Remember(definition.Key, value)
			}
			delete(byKey, definition.Key)
		}
		items = append(items, ListItem{Definition: definition, Record: record, Value: value, Registered: true})
	}
	for _, record := range byKey {
		definition := Definition{
			Key: record.ConfigKey, Module: record.Module, ValueType: record.ValueType,
			Description: record.Description, Readonly: true, Sensitive: record.IsSensitive, Control: "readonly",
		}
		items = append(items, ListItem{Definition: definition, Record: record, Value: record.ConfigValue, Registered: false})
	}
	sort.Slice(items, func(i, j int) bool { return items[i].Definition.Key < items[j].Definition.Key })
	return items, nil
}
