package appconfig

import (
	"errors"
	"fmt"
	"strings"

	"hyapp-admin-server/internal/appctx"
	"hyapp-admin-server/internal/model"
)

const (
	runtimeCapabilitiesGroup = "runtime-capabilities"

	activityLeaderboardScopeKey          = "activity_leaderboard_scope"
	activityLeaderboardScopeAppGlobal    = "app_global"
	activityLeaderboardScopeViewerRegion = "viewer_region"

	resourceEquipCommandIDPolicyKey            = "resource_equip_command_id_policy"
	resourceEquipCommandIDPolicyLegacyOptional = "legacy_optional"
	resourceEquipCommandIDPolicyRequired       = "required"
)

type RuntimeCapabilitiesConfig struct {
	AppCode                      string `json:"appCode"`
	ActivityLeaderboardScope     string `json:"activityLeaderboardScope"`
	ResourceEquipCommandIDPolicy string `json:"resourceEquipCommandIdPolicy"`
	UpdatedAtMS                  int64  `json:"updatedAtMs"`
}

func defaultRuntimeCapabilitiesConfig(appCode string) RuntimeCapabilitiesConfig {
	return RuntimeCapabilitiesConfig{
		AppCode:                      appctx.Normalize(appCode),
		ActivityLeaderboardScope:     activityLeaderboardScopeAppGlobal,
		ResourceEquipCommandIDPolicy: resourceEquipCommandIDPolicyLegacyOptional,
	}
}

func (s *AppConfigService) GetRuntimeCapabilitiesConfig(appCode string) (RuntimeCapabilitiesConfig, error) {
	appCode = appctx.Normalize(appCode)
	items, err := s.store.ListOwnedAppConfigs(appCode, runtimeCapabilitiesGroup)
	if err != nil {
		return RuntimeCapabilitiesConfig{}, err
	}
	return runtimeCapabilitiesConfigFromModels(appCode, items)
}

func (s *AppConfigService) UpdateRuntimeCapabilitiesConfig(appCode string, request runtimeCapabilitiesConfigRequest) (RuntimeCapabilitiesConfig, error) {
	items, err := runtimeCapabilitiesConfigModels(appCode, request)
	if err != nil {
		return RuntimeCapabilitiesConfig{}, err
	}
	// 两项能力必须在同一批 upsert 中写入当前鉴权 App，避免页面保存后 Gateway 看到半套策略。
	if err := s.store.UpsertScopedAppConfigs(appctx.Normalize(appCode), items); err != nil {
		return RuntimeCapabilitiesConfig{}, err
	}
	return s.GetRuntimeCapabilitiesConfig(appCode)
}

func runtimeCapabilitiesConfigModels(appCode string, request runtimeCapabilitiesConfigRequest) ([]model.AppConfig, error) {
	appCode = appctx.Normalize(appCode)
	leaderboardScope := strings.ToLower(strings.TrimSpace(request.ActivityLeaderboardScope))
	if leaderboardScope != activityLeaderboardScopeAppGlobal && leaderboardScope != activityLeaderboardScopeViewerRegion {
		return nil, errors.New("活动榜单范围不正确")
	}
	equipPolicy := strings.ToLower(strings.TrimSpace(request.ResourceEquipCommandIDPolicy))
	if equipPolicy != resourceEquipCommandIDPolicyLegacyOptional && equipPolicy != resourceEquipCommandIDPolicyRequired {
		return nil, errors.New("资源佩戴 command_id 策略不正确")
	}
	return []model.AppConfig{
		{
			AppCode:     appCode,
			Group:       runtimeCapabilitiesGroup,
			Key:         activityLeaderboardScopeKey,
			Value:       leaderboardScope,
			Description: "活动榜单范围：app_global 或 viewer_region",
		},
		{
			AppCode:     appCode,
			Group:       runtimeCapabilitiesGroup,
			Key:         resourceEquipCommandIDPolicyKey,
			Value:       equipPolicy,
			Description: "资源佩戴幂等键策略：legacy_optional 或 required",
		},
	}, nil
}

func runtimeCapabilitiesConfigFromModels(appCode string, items []model.AppConfig) (RuntimeCapabilitiesConfig, error) {
	config := defaultRuntimeCapabilitiesConfig(appCode)
	for _, item := range items {
		value := strings.ToLower(strings.TrimSpace(item.Value))
		switch strings.TrimSpace(item.Key) {
		case activityLeaderboardScopeKey:
			if value != activityLeaderboardScopeAppGlobal && value != activityLeaderboardScopeViewerRegion {
				return RuntimeCapabilitiesConfig{}, fmt.Errorf("活动榜单范围配置无效: %s", value)
			}
			config.ActivityLeaderboardScope = value
		case resourceEquipCommandIDPolicyKey:
			if value != resourceEquipCommandIDPolicyLegacyOptional && value != resourceEquipCommandIDPolicyRequired {
				return RuntimeCapabilitiesConfig{}, fmt.Errorf("资源佩戴 command_id 策略配置无效: %s", value)
			}
			config.ResourceEquipCommandIDPolicy = value
		default:
			continue
		}
		if item.UpdatedAtMS > config.UpdatedAtMS {
			config.UpdatedAtMS = item.UpdatedAtMS
		}
	}
	return config, nil
}
