package auth

import (
	"context"
	"time"

	"hyapp/pkg/appcode"
	"hyapp/pkg/xerr"
	authdomain "hyapp/services/user-service/internal/domain/auth"
)

const (
	defaultMaxAccountsPerDevice = int32(1)
	registerRiskConfigCacheTTL  = 5 * time.Minute
)

// GetRegisterRiskConfig 返回当前 App 的注册风控配置。
// Redis 只缓存 5 分钟以降低登录注册热路径回源；缓存异常不阻断读取，避免缓存故障改变注册策略。
func (s *Service) GetRegisterRiskConfig(ctx context.Context) (authdomain.RegisterRiskConfig, error) {
	appCode := appcode.FromContext(ctx)
	if s.registerRiskConfigCache != nil {
		config, ok, err := s.registerRiskConfigCache.GetRegisterRiskConfig(ctx, appCode)
		if err == nil && ok {
			return normalizeRegisterRiskConfig(config), nil
		}
	}
	config, err := s.loadRegisterRiskConfig(ctx, appCode)
	if err != nil {
		return authdomain.RegisterRiskConfig{}, err
	}
	if s.registerRiskConfigCache != nil {
		// 读路径写缓存是加速动作；失败时仍返回 MySQL 事实，后续请求会继续尝试刷新缓存。
		_ = s.registerRiskConfigCache.SetRegisterRiskConfig(ctx, config, registerRiskConfigCacheTTL)
	}
	return config, nil
}

// UpdateRegisterRiskConfig 保存注册风控配置并立即刷新 Redis。
// MySQL 是持久事实，Redis 是注册热路径缓存；更新后同步刷新同一个 key，避免运营保存后继续命中旧值。
func (s *Service) UpdateRegisterRiskConfig(ctx context.Context, maxAccountsPerDevice int32, operatorAdminID int64) (authdomain.RegisterRiskConfig, error) {
	if maxAccountsPerDevice < 1 {
		return authdomain.RegisterRiskConfig{}, xerr.New(xerr.InvalidArgument, "max_accounts_per_device must be greater than 0")
	}
	if s.authRepository == nil {
		return authdomain.RegisterRiskConfig{}, xerr.New(xerr.Unavailable, "auth repository is not configured")
	}
	nowMs := s.now().UTC().UnixMilli()
	config, err := s.authRepository.UpsertRegisterRiskConfig(ctx, authdomain.RegisterRiskConfig{
		AppCode:              appcode.FromContext(ctx),
		MaxAccountsPerDevice: maxAccountsPerDevice,
		UpdatedByAdminID:     operatorAdminID,
		CreatedAtMs:          nowMs,
		UpdatedAtMs:          nowMs,
	})
	if err != nil {
		return authdomain.RegisterRiskConfig{}, err
	}
	config = normalizeRegisterRiskConfig(config)
	if s.registerRiskConfigCache != nil {
		if err := s.registerRiskConfigCache.SetRegisterRiskConfig(ctx, config, registerRiskConfigCacheTTL); err != nil {
			// 保存成功但缓存未刷新时返回错误，提示后台重试；否则注册链路可能在 5 分钟内继续读取旧配置。
			return authdomain.RegisterRiskConfig{}, err
		}
	}
	return config, nil
}

func (s *Service) loadRegisterRiskConfig(ctx context.Context, appCode string) (authdomain.RegisterRiskConfig, error) {
	if s.authRepository == nil {
		return defaultRegisterRiskConfig(appCode), nil
	}
	config, err := s.authRepository.GetRegisterRiskConfig(ctx, appCode)
	if xerr.IsCode(err, xerr.NotFound) {
		return defaultRegisterRiskConfig(appCode), nil
	}
	if err != nil {
		return authdomain.RegisterRiskConfig{}, err
	}
	return normalizeRegisterRiskConfig(config), nil
}

func defaultRegisterRiskConfig(appCode string) authdomain.RegisterRiskConfig {
	return authdomain.RegisterRiskConfig{
		AppCode:              appcode.Normalize(appCode),
		MaxAccountsPerDevice: defaultMaxAccountsPerDevice,
	}
}

func normalizeRegisterRiskConfig(config authdomain.RegisterRiskConfig) authdomain.RegisterRiskConfig {
	config.AppCode = appcode.Normalize(config.AppCode)
	if config.MaxAccountsPerDevice < 1 {
		config.MaxAccountsPerDevice = defaultMaxAccountsPerDevice
	}
	return config
}
