package roomrocket

import (
	"context"
	"errors"
	"testing"

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

func TestConfigFromUpdateRequestUsesContextAppCode(t *testing.T) {
	request := updateRoomRocketConfigRequest{Levels: defaultConfig("ignored").Levels}
	config := configFromUpdateRequest(appctx.WithContext(context.Background(), "LALU"), request)
	if config.AppCode != "lalu" {
		t.Fatalf("config app code should come from context: %+v", config)
	}
	if _, err := normalizeConfig(config); err != nil {
		t.Fatalf("normalizeConfig should accept context app code: %v", err)
	}
}

func TestNormalizeConfigDefaultsAndSortsLevels(t *testing.T) {
	config, err := normalizeConfig(RoomRocketConfig{
		AppCode:       "lalu",
		LaunchDelayMS: defaultLaunchDelayMS,
		Levels: []RoomRocketLevelConfig{
			{Level: 2, FuelThreshold: 300},
			{Level: 1, FuelThreshold: 100},
			{Level: 3, FuelThreshold: 600},
			{Level: 4, FuelThreshold: 1_000},
			{Level: 5, FuelThreshold: 1_500},
		},
	})
	if err != nil {
		t.Fatalf("normalizeConfig failed: %v", err)
	}
	if config.FuelSource != defaultFuelSource || config.LaunchDelayMS != defaultLaunchDelayMS || config.BroadcastScope != defaultBroadcastScope {
		t.Fatalf("default fields mismatch: %+v", config)
	}
	if config.Levels[0].Level != 1 || config.Levels[4].Level != 5 {
		t.Fatalf("levels should be sorted by level: %+v", config.Levels)
	}
}

func TestNormalizeConfigKeepsRewardQuantityAndDefaultsOldItems(t *testing.T) {
	config := defaultConfig("lalu")
	config.Levels[0].InRoomRewards = []RoomRocketRewardItem{
		{RewardItemID: "coin", ResourceGroupID: 1001, Weight: 100, Quantity: 2},
		{RewardItemID: "mic-wave", ResourceGroupID: 1002, Weight: 100},
	}
	normalized, err := normalizeConfig(config)
	if err != nil {
		t.Fatalf("normalizeConfig failed: %v", err)
	}
	rewards := normalized.Levels[0].InRoomRewards
	if rewards[0].Quantity != 2 || rewards[1].Quantity != 1 {
		t.Fatalf("reward quantity must be preserved and defaulted: %+v", rewards)
	}
}

func TestDefaultConfigKeepsOperationalDefaults(t *testing.T) {
	config, err := normalizeConfig(defaultConfig("lalu"))
	if err != nil {
		t.Fatalf("normalizeConfig(defaultConfig) failed: %v", err)
	}
	if !config.BroadcastEnabled || config.LaunchDelayMS != defaultLaunchDelayMS || len(config.Levels) != roomRocketLevelCount {
		t.Fatalf("default config mismatch: %+v", config)
	}
}

func TestNormalizeConfigRejectsInvalidLevels(t *testing.T) {
	tests := []struct {
		name   string
		config RoomRocketConfig
	}{
		{name: "missing_level", config: RoomRocketConfig{AppCode: "lalu", Levels: []RoomRocketLevelConfig{{Level: 1, FuelThreshold: 1}}}},
		{name: "duplicate", config: RoomRocketConfig{AppCode: "lalu", Levels: []RoomRocketLevelConfig{
			{Level: 1, FuelThreshold: 1}, {Level: 1, FuelThreshold: 2}, {Level: 3, FuelThreshold: 3}, {Level: 4, FuelThreshold: 4}, {Level: 5, FuelThreshold: 5},
		}}},
		{name: "zero_threshold", config: RoomRocketConfig{AppCode: "lalu", Levels: []RoomRocketLevelConfig{
			{Level: 1, FuelThreshold: 0}, {Level: 2, FuelThreshold: 2}, {Level: 3, FuelThreshold: 3}, {Level: 4, FuelThreshold: 4}, {Level: 5, FuelThreshold: 5},
		}}},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			_, err := normalizeConfig(test.config)
			if !errors.Is(err, ErrInvalidArgument) {
				t.Fatalf("normalizeConfig should reject %s with ErrInvalidArgument, got %v", test.name, err)
			}
		})
	}
}

func TestNormalizeConfigRejectsIncompleteRewardAndFuelRule(t *testing.T) {
	config := defaultConfig("lalu")
	config.Levels[0].InRoomRewards = []RoomRocketRewardItem{{ResourceGroupID: 0, Weight: 100}}
	if _, err := normalizeConfig(config); !errors.Is(err, ErrInvalidArgument) {
		t.Fatalf("reward without resource group should be invalid, got %v", err)
	}

	config = defaultConfig("lalu")
	config.GiftFuelRules = []GiftFuelRuleConfig{{GiftID: "gift-1"}}
	if _, err := normalizeConfig(config); !errors.Is(err, ErrInvalidArgument) {
		t.Fatalf("fuel rule without multiplier or fixed fuel should be invalid, got %v", err)
	}
}
