package mysql

import (
	"context"
	"fmt"
	"testing"

	"hyapp/internal/testutil/mysqlschema"
	"hyapp/pkg/appcode"
	domain "hyapp/services/lucky-gift-service/internal/domain/luckygift"
)

func experimentTestFixedRule(poolID string, targetRTPPPM int64) domain.RuleConfig {
	return domain.RuleConfig{
		PoolID:                   poolID,
		Enabled:                  true,
		StrategyVersion:          domain.StrategyFixedV2,
		TargetRTPPPM:             targetRTPPPM,
		PoolRatePPM:              980_000,
		SettlementWindowWager:    1_000_000,
		ControlBandPPM:           10_000,
		GiftPriceReference:       100,
		NoviceMaxEquivalentDraws: 2_000,
		NormalMaxEquivalentDraws: 20_000,
		Stages: []domain.RuleStage{
			{Stage: domain.StageNovice, Tiers: []domain.RuleTier{
				{Stage: domain.StageNovice, TierID: "novice_1x", MultiplierPPM: 1_000_000, BaseWeightPPM: 1_000_000, Enabled: true},
			}},
		},
	}
}

// 回归：AB 实验完整生命周期——创建时原子发布 treatment、分流按白名单/哈希钉住版本、
// 实验期常规发布被拒绝、暂停回落 control、结束时获胜配置重发布为最新版本并恢复默认语义。
func TestLuckyGiftExperimentLifecycle(t *testing.T) {
	caller := mysqlschema.CallerFile(t, 1)
	schema := mysqlschema.New(t, mysqlschema.Config{
		EnvVar:         "LUCKY_GIFT_SERVICE_MYSQL_TEST_DSN",
		InitDBPath:     mysqlschema.InitDBPath(t, caller, "..", "..", "..", "deploy", "mysql", "initdb", "001_lucky_gift_service.sql"),
		DatabasePrefix: "hy_lucky_gift",
	})
	repo := &Repository{db: schema.DB}
	ctx := appcode.WithContext(context.Background(), "lalu")

	control := experimentTestFixedRule("super_lucky", 950_000)
	if _, err := repo.PublishLuckyGiftRuleConfig(ctx, control, 1_700_000_000_000); err != nil {
		t.Fatalf("publish control config: %v", err)
	}

	treatment := experimentTestFixedRule("super_lucky", 960_000)
	experiment, published, err := repo.CreateLuckyGiftExperiment(ctx, domain.CreateExperimentCommand{
		Name:                "super_lucky v2 rtp+1",
		TreatmentConfig:     treatment,
		TreatmentTrafficPPM: 0,
		OperatorAdminID:     7,
		Overrides:           []domain.ExperimentOverride{{UserKey: "1001", Arm: domain.ExperimentArmTreatment}},
	}, 1_700_000_100_000)
	if err != nil {
		t.Fatalf("create experiment: %v", err)
	}
	if experiment.ControlRuleVersion != 1 || experiment.TreatmentRuleVersion != 2 || published.RuleVersion != 2 {
		t.Fatalf("experiment pinned versions control=%d treatment=%d published=%d, want 1/2/2",
			experiment.ControlRuleVersion, experiment.TreatmentRuleVersion, published.RuleVersion)
	}

	// 白名单用户解析到 treatment v2；普通用户在 0% 放量下解析到 control v1。
	resolved, exists, err := repo.resolveLuckyGiftRuleConfigForUser(ctx, schema.DB, "lalu", "super_lucky", "1001", false)
	if err != nil || !exists || resolved.RuleVersion != 2 {
		t.Fatalf("override user resolved version=%d exists=%v err=%v, want treatment v2", resolved.RuleVersion, exists, err)
	}
	resolved, exists, err = repo.resolveLuckyGiftRuleConfigForUser(ctx, schema.DB, "lalu", "super_lucky", "2002", false)
	if err != nil || !exists || resolved.RuleVersion != 1 {
		t.Fatalf("hash user resolved version=%d exists=%v err=%v, want control v1 at 0%% traffic", resolved.RuleVersion, exists, err)
	}

	// 实验期间常规发布必须被拒绝，避免运营发布一个静默无效的版本。
	if _, err := repo.PublishLuckyGiftRuleConfig(ctx, control, 1_700_000_200_000); err == nil {
		t.Fatal("regular publish should be rejected while an experiment is active")
	}
	// 同奖池不允许并发第二个实验。
	if _, _, err := repo.CreateLuckyGiftExperiment(ctx, domain.CreateExperimentCommand{
		Name: "dup", TreatmentConfig: treatment, OperatorAdminID: 7,
	}, 1_700_000_200_000); err == nil {
		t.Fatal("second active experiment on the same pool should be rejected")
	}

	// 放量 100% 后普通用户进入 treatment；确定性哈希保证任何用户都命中 bucket < 1000000。
	if _, err := repo.UpdateLuckyGiftExperiment(ctx, domain.UpdateExperimentCommand{
		ExperimentID:        experiment.ExperimentID,
		TreatmentTrafficPPM: 1_000_000,
	}, 1_700_000_300_000); err != nil {
		t.Fatalf("update experiment traffic: %v", err)
	}
	resolved, _, err = repo.resolveLuckyGiftRuleConfigForUser(ctx, schema.DB, "lalu", "super_lucky", "2002", false)
	if err != nil || resolved.RuleVersion != 2 {
		t.Fatalf("full ramp resolved version=%d err=%v, want treatment v2", resolved.RuleVersion, err)
	}

	// 暂停后包括白名单在内所有用户回落 control。
	if _, err := repo.UpdateLuckyGiftExperiment(ctx, domain.UpdateExperimentCommand{
		ExperimentID:        experiment.ExperimentID,
		TreatmentTrafficPPM: -1,
		Status:              domain.ExperimentStatusPaused,
	}, 1_700_000_400_000); err != nil {
		t.Fatalf("pause experiment: %v", err)
	}
	for _, userKey := range []string{"1001", "2002"} {
		resolved, _, err = repo.resolveLuckyGiftRuleConfigForUser(ctx, schema.DB, "lalu", "super_lucky", userKey, false)
		if err != nil || resolved.RuleVersion != 1 {
			t.Fatalf("paused experiment user %s resolved version=%d err=%v, want control v1", userKey, resolved.RuleVersion, err)
		}
	}

	// 结束实验：treatment 获胜 → 快照重发布为 v3，实验收口，默认"最新版本生效"恢复。
	ended, finalConfig, err := repo.EndLuckyGiftExperiment(ctx, domain.EndExperimentCommand{
		ExperimentID:    experiment.ExperimentID,
		WinnerArm:       domain.ExperimentArmTreatment,
		OperatorAdminID: 7,
	}, 1_700_000_500_000)
	if err != nil {
		t.Fatalf("end experiment: %v", err)
	}
	if ended.Status != domain.ExperimentStatusCompleted || ended.WinnerRuleVersion != 2 || ended.FinalRuleVersion != 3 || finalConfig.RuleVersion != 3 {
		t.Fatalf("ended experiment = %+v final=%d, want completed winner v2 republished as v3", ended, finalConfig.RuleVersion)
	}
	if finalConfig.TargetRTPPPM != 960_000 {
		t.Fatalf("final config target rtp = %d, want treatment content 960000", finalConfig.TargetRTPPPM)
	}
	resolved, _, err = repo.resolveLuckyGiftRuleConfigForUser(ctx, schema.DB, "lalu", "super_lucky", "2002", false)
	if err != nil || resolved.RuleVersion != 3 {
		t.Fatalf("post-experiment resolved version=%d err=%v, want latest v3", resolved.RuleVersion, err)
	}
	// 实验收口后常规发布恢复可用。
	if _, err := repo.PublishLuckyGiftRuleConfig(ctx, control, 1_700_000_600_000); err != nil {
		t.Fatalf("regular publish after experiment completion: %v", err)
	}
	// 结束后的实验不可再修改。
	if _, err := repo.UpdateLuckyGiftExperiment(ctx, domain.UpdateExperimentCommand{
		ExperimentID:        experiment.ExperimentID,
		TreatmentTrafficPPM: 1,
	}, 1_700_000_700_000); err == nil {
		t.Fatal("completed experiment must be immutable")
	}
}

// 回归：实验列表带分组统计——抽奖事实按 rule_version 聚合到对应组，窗口从实验开始时间起算。
func TestLuckyGiftExperimentArmStats(t *testing.T) {
	caller := mysqlschema.CallerFile(t, 1)
	schema := mysqlschema.New(t, mysqlschema.Config{
		EnvVar:         "LUCKY_GIFT_SERVICE_MYSQL_TEST_DSN",
		InitDBPath:     mysqlschema.InitDBPath(t, caller, "..", "..", "..", "deploy", "mysql", "initdb", "001_lucky_gift_service.sql"),
		DatabasePrefix: "hy_lucky_gift",
	})
	repo := &Repository{db: schema.DB}
	ctx := appcode.WithContext(context.Background(), "lalu")

	if _, err := repo.PublishLuckyGiftRuleConfig(ctx, experimentTestFixedRule("lucky", 950_000), 1_700_000_000_000); err != nil {
		t.Fatalf("publish control config: %v", err)
	}
	experiment, _, err := repo.CreateLuckyGiftExperiment(ctx, domain.CreateExperimentCommand{
		Name:                "stats",
		TreatmentConfig:     experimentTestFixedRule("lucky", 960_000),
		TreatmentTrafficPPM: 500_000,
		OperatorAdminID:     7,
	}, 1_700_000_100_000)
	if err != nil {
		t.Fatalf("create experiment: %v", err)
	}
	seedDraw := func(drawID, commandID string, ruleVersion, userID, spent, reward, createdAtMS int64) {
		t.Helper()
		if _, err := schema.DB.Exec(`
			INSERT INTO lucky_draw_records (
			  app_code, draw_id, command_id, user_id, device_id, room_id, anchor_id, gift_id, pool_id,
			  rule_version, experience_pool, selected_tier_id, coin_spent,
			  base_reward_coins, effective_reward_coins, reward_status, rtp_window_index, gift_rtp_window_index,
			  candidate_tiers_json, pool_snapshot_json, rtp_snapshot_json,
			  paid_at_ms, created_at_ms, updated_at_ms
			) VALUES ('lalu', ?, ?, ?, 'd', 'room', 'anchor', 'lucky', 'lucky', ?, 'novice', 't', ?, ?, ?, 'granted', 1, 1, '{}', '{}', '{}', ?, ?, ?)`,
			drawID, commandID, userID, ruleVersion, spent, reward, reward, createdAtMS, createdAtMS, createdAtMS,
		); err != nil {
			t.Fatalf("seed draw %s: %v", drawID, err)
		}
	}
	// 实验开始前的旧版本抽奖不计入统计窗口。
	seedDraw("d0", "c0", 1, 1, 1_000, 900, 1_600_000_000_000)
	seedDraw("d1", "c1", 1, 1, 1_000, 900, 1_700_000_200_000)
	seedDraw("d2", "c2", 1, 2, 1_000, 800, 1_700_000_200_001)
	seedDraw("d3", "c3", 2, 3, 2_000, 2_200, 1_700_000_200_002)

	experiments, err := repo.ListLuckyGiftExperiments(ctx, domain.ExperimentQuery{AppCode: "lalu", PoolID: "lucky", WithStats: true})
	if err != nil {
		t.Fatalf("list experiments with stats: %v", err)
	}
	if len(experiments) != 1 || len(experiments[0].ArmStats) != 2 {
		t.Fatalf("experiments=%d armStats=%v, want 1 experiment with 2 arms", len(experiments), experiments)
	}
	statsByArm := map[string]domain.ExperimentArmStats{}
	for _, stats := range experiments[0].ArmStats {
		statsByArm[stats.Arm] = stats
	}
	controlStats := statsByArm[domain.ExperimentArmControl]
	if controlStats.TotalDraws != 2 || controlStats.UniqueUsers != 2 || controlStats.TotalSpentCoins != 2_000 || controlStats.TotalRewardCoins != 1_700 {
		t.Fatalf("control stats = %+v, want 2 draws / 2 users / 2000 spent / 1700 reward", controlStats)
	}
	if controlStats.ActualRTPPPM != 850_000 {
		t.Fatalf("control rtp = %d, want 850000 ppm", controlStats.ActualRTPPPM)
	}
	treatmentStats := statsByArm[domain.ExperimentArmTreatment]
	if treatmentStats.TotalDraws != 1 || treatmentStats.TotalSpentCoins != 2_000 || treatmentStats.ActualRTPPPM != 1_100_000 {
		t.Fatalf("treatment stats = %+v, want 1 draw / 2000 spent / 1.1 rtp", treatmentStats)
	}
	if controlStats.StrategyVersion != domain.StrategyFixedV2 || treatmentStats.StrategyVersion != domain.StrategyFixedV2 {
		t.Fatalf("arm strategy versions = %q/%q, want fixed_v2", controlStats.StrategyVersion, treatmentStats.StrategyVersion)
	}
	_ = experiment
}

// 回归：实验组允许跨代策略。旧客户端缺 device_id 时 V3 只跳过设备限额，wallet 回执仍提供 paid_at，
// 因此 fixed_v2 与 dynamic_v3 可以安全按同一用户键分流并保持各自不可变版本。
func TestCreateExperimentAllowsMixedStrategyArms(t *testing.T) {
	caller := mysqlschema.CallerFile(t, 1)
	schema := mysqlschema.New(t, mysqlschema.Config{
		EnvVar:         "LUCKY_GIFT_SERVICE_MYSQL_TEST_DSN",
		InitDBPath:     mysqlschema.InitDBPath(t, caller, "..", "..", "..", "deploy", "mysql", "initdb", "001_lucky_gift_service.sql"),
		DatabasePrefix: "hy_lucky_gift",
	})
	repo := &Repository{db: schema.DB}
	ctx := appcode.WithContext(context.Background(), "lalu")
	if _, err := repo.PublishLuckyGiftRuleConfig(ctx, experimentTestFixedRule("lucky", 950_000), 1_700_000_000_000); err != nil {
		t.Fatalf("publish fixed control: %v", err)
	}
	dynamicTreatment := dynamicMySQLTestRule("lucky")
	experiment, published, err := repo.CreateLuckyGiftExperiment(ctx, domain.CreateExperimentCommand{
		Name: "mixed", TreatmentConfig: dynamicTreatment, OperatorAdminID: 7,
		Overrides: []domain.ExperimentOverride{{UserKey: "1001", Arm: domain.ExperimentArmTreatment}},
	}, 1_700_000_100_000)
	if err != nil {
		t.Fatalf("create mixed-strategy experiment: %v", err)
	}
	if experiment.ControlRuleVersion != 1 || experiment.TreatmentRuleVersion != 2 || published.StrategyVersion != domain.StrategyDynamicV3 {
		t.Fatalf("mixed experiment versions=%d/%d published strategy=%q", experiment.ControlRuleVersion, experiment.TreatmentRuleVersion, published.StrategyVersion)
	}
	control, exists, err := repo.resolveLuckyGiftRuleConfigForUser(ctx, schema.DB, "lalu", "lucky", "2002", false)
	if err != nil || !exists || control.StrategyVersion != domain.StrategyFixedV2 {
		t.Fatalf("mixed control resolution=%+v exists=%v err=%v", control, exists, err)
	}
	treatment, exists, err := repo.resolveLuckyGiftRuleConfigForUser(ctx, schema.DB, "lalu", "lucky", "1001", false)
	if err != nil || !exists || treatment.StrategyVersion != domain.StrategyDynamicV3 {
		t.Fatalf("mixed treatment resolution=%+v exists=%v err=%v", treatment, exists, err)
	}
}

// 回归：零冷启动守卫上线前的遗留 dynamic_v3 版本行残留 initial_pool_coins；
// 以它为获胜方收口时重发布入口必须清零，否则实验永远无法以 control 结束。
func TestEndExperimentRepublishesLegacyDirtyDynamicControl(t *testing.T) {
	caller := mysqlschema.CallerFile(t, 1)
	schema := mysqlschema.New(t, mysqlschema.Config{
		EnvVar:         "LUCKY_GIFT_SERVICE_MYSQL_TEST_DSN",
		InitDBPath:     mysqlschema.InitDBPath(t, caller, "..", "..", "..", "deploy", "mysql", "initdb", "001_lucky_gift_service.sql"),
		DatabasePrefix: "hy_lucky_gift",
	})
	repo := &Repository{db: schema.DB}
	ctx := appcode.WithContext(context.Background(), "lalu")
	if _, err := repo.PublishLuckyGiftRuleConfig(ctx, dynamicMySQLTestRule("dirty"), 1_700_000_000_000); err != nil {
		t.Fatalf("publish dynamic control: %v", err)
	}
	// 模拟迁移前发布的脏行：配置里残留 initial_pool_coins，运行时只做读时清零不回写。
	if _, err := schema.DB.Exec(`
		UPDATE lucky_gift_rule_versions SET initial_pool_coins = 1000000
		WHERE app_code = 'lalu' AND pool_id = 'dirty' AND rule_version = 1`); err != nil {
		t.Fatalf("seed dirty initial_pool_coins: %v", err)
	}
	experiment, _, err := repo.CreateLuckyGiftExperiment(ctx, domain.CreateExperimentCommand{
		Name: "dirty-control", TreatmentConfig: dynamicMySQLTestRule("dirty"), OperatorAdminID: 7,
	}, 1_700_000_100_000)
	if err != nil {
		t.Fatalf("create dynamic experiment: %v", err)
	}
	ended, finalConfig, err := repo.EndLuckyGiftExperiment(ctx, domain.EndExperimentCommand{
		ExperimentID: experiment.ExperimentID, WinnerArm: domain.ExperimentArmControl, OperatorAdminID: 7,
	}, 1_700_000_200_000)
	if err != nil {
		t.Fatalf("end experiment with dirty dynamic control as winner: %v", err)
	}
	if ended.Status != domain.ExperimentStatusCompleted || finalConfig.InitialPoolCoins != 0 {
		t.Fatalf("ended=%+v final initial_pool_coins=%d, want completed with zeroed coins", ended, finalConfig.InitialPoolCoins)
	}
}

// 回归：白名单累计上限在事务内核算，多次追加不能绕过单次 500 的入口校验。
func TestSetExperimentOverridesEnforcesCumulativeCap(t *testing.T) {
	caller := mysqlschema.CallerFile(t, 1)
	schema := mysqlschema.New(t, mysqlschema.Config{
		EnvVar:         "LUCKY_GIFT_SERVICE_MYSQL_TEST_DSN",
		InitDBPath:     mysqlschema.InitDBPath(t, caller, "..", "..", "..", "deploy", "mysql", "initdb", "001_lucky_gift_service.sql"),
		DatabasePrefix: "hy_lucky_gift",
	})
	repo := &Repository{db: schema.DB}
	ctx := appcode.WithContext(context.Background(), "lalu")
	if _, err := repo.PublishLuckyGiftRuleConfig(ctx, experimentTestFixedRule("cap", 950_000), 1_700_000_000_000); err != nil {
		t.Fatalf("publish control: %v", err)
	}
	experiment, _, err := repo.CreateLuckyGiftExperiment(ctx, domain.CreateExperimentCommand{
		Name: "cap", TreatmentConfig: experimentTestFixedRule("cap", 960_000), OperatorAdminID: 7,
	}, 1_700_000_100_000)
	if err != nil {
		t.Fatalf("create experiment: %v", err)
	}
	batch := func(from, to int) []domain.ExperimentOverride {
		out := make([]domain.ExperimentOverride, 0, to-from)
		for i := from; i < to; i++ {
			out = append(out, domain.ExperimentOverride{UserKey: fmt.Sprintf("%d", i), Arm: domain.ExperimentArmTreatment})
		}
		return out
	}
	if _, err := repo.SetLuckyGiftExperimentOverrides(ctx, domain.SetExperimentOverridesCommand{
		ExperimentID: experiment.ExperimentID, Upserts: batch(0, 500), OperatorAdminID: 7,
	}, 1_700_000_200_000); err != nil {
		t.Fatalf("first 500 overrides should be accepted: %v", err)
	}
	if _, err := repo.SetLuckyGiftExperimentOverrides(ctx, domain.SetExperimentOverridesCommand{
		ExperimentID: experiment.ExperimentID, Upserts: batch(500, 501), OperatorAdminID: 7,
	}, 1_700_000_300_000); err == nil {
		t.Fatal("501st override must be rejected by the cumulative cap")
	}
}

// 回归：006 迁移在全新库上可重复执行，生成列唯一键允许多个 completed 实验但只允许一个未完成实验。
func TestExperimentMigrationIsIdempotentAndEnforcesSingleActive(t *testing.T) {
	caller := mysqlschema.CallerFile(t, 1)
	schema := mysqlschema.New(t, mysqlschema.Config{
		EnvVar:         "LUCKY_GIFT_SERVICE_MYSQL_TEST_DSN",
		InitDBPath:     mysqlschema.InitDBPath(t, caller, "..", "..", "..", "deploy", "mysql", "initdb", "001_lucky_gift_service.sql"),
		DatabasePrefix: "hy_lucky_gift",
	})
	migrationPath := mysqlschema.InitDBPath(t, caller, "..", "..", "..", "deploy", "mysql", "migrations", "006_ab_experiments.sql")
	runLuckyGiftSQLScript(t, schema.DB, migrationPath)
	runLuckyGiftSQLScript(t, schema.DB, migrationPath)

	insert := func(id, status string) error {
		_, err := schema.DB.Exec(`
			INSERT INTO lucky_gift_experiments (
			  app_code, experiment_id, pool_id, name, control_rule_version, treatment_rule_version,
			  treatment_traffic_ppm, bucket_salt, status, started_at_ms, created_at_ms, updated_at_ms
			) VALUES ('lalu', ?, 'lucky', 'n', 1, 2, 0, 's', ?, 1, 1, 1)`, id, status)
		return err
	}
	if err := insert("e1", "completed"); err != nil {
		t.Fatalf("insert completed experiment: %v", err)
	}
	if err := insert("e2", "completed"); err != nil {
		t.Fatalf("second completed experiment should not hit the active unique key: %v", err)
	}
	if err := insert("e3", "running"); err != nil {
		t.Fatalf("insert running experiment: %v", err)
	}
	if err := insert("e4", "paused"); err == nil {
		t.Fatal("second unfinished experiment must violate uk_lucky_gift_experiments_active_pool")
	}
}

// 回归：v2 高水位加权滞回标志按奖池单行共享，两组三元组不同会互踩（control 清 treatment 的标志、
// 阈值不同的组按对方状态加权付奖）；实验创建必须硬性要求两组三元组一致。
func TestCreateLuckyGiftExperimentRejectsMismatchedV2HighWaterBoost(t *testing.T) {
	caller := mysqlschema.CallerFile(t, 1)
	schema := mysqlschema.New(t, mysqlschema.Config{
		EnvVar:         "LUCKY_GIFT_SERVICE_MYSQL_TEST_DSN",
		InitDBPath:     mysqlschema.InitDBPath(t, caller, "..", "..", "..", "deploy", "mysql", "initdb", "001_lucky_gift_service.sql"),
		DatabasePrefix: "hy_lucky_gift_expboost",
	})
	repo := &Repository{db: schema.DB}
	ctx := appcode.WithContext(context.Background(), "lalu")

	control := experimentTestFixedRule("boost_pool", 950_000)
	control.V2HighWaterBoostThresholdCoins = 2_000_000
	control.V2HighWaterBoostFactorPPM = 1_500_000
	control.V2HighWaterBoostRecoverCoins = 1_000_000
	if _, err := repo.PublishLuckyGiftRuleConfig(ctx, control, 1_700_000_000_000); err != nil {
		t.Fatalf("publish control config: %v", err)
	}

	// control 开启加权、treatment 关闭：正是会互踩滞回标志的灰度形态，必须被拒绝。
	mismatched := experimentTestFixedRule("boost_pool", 950_000)
	if _, _, err := repo.CreateLuckyGiftExperiment(ctx, domain.CreateExperimentCommand{
		Name: "boost off arm", TreatmentConfig: mismatched, OperatorAdminID: 7,
	}, 1_700_000_100_000); err == nil {
		t.Fatal("experiment with mismatched v2 boost triples should be rejected")
	}

	// 三元组逐字段一致时照常创建。
	matched := experimentTestFixedRule("boost_pool", 960_000)
	matched.V2HighWaterBoostThresholdCoins = control.V2HighWaterBoostThresholdCoins
	matched.V2HighWaterBoostFactorPPM = control.V2HighWaterBoostFactorPPM
	matched.V2HighWaterBoostRecoverCoins = control.V2HighWaterBoostRecoverCoins
	if _, _, err := repo.CreateLuckyGiftExperiment(ctx, domain.CreateExperimentCommand{
		Name: "boost aligned", TreatmentConfig: matched, OperatorAdminID: 7,
	}, 1_700_000_200_000); err != nil {
		t.Fatalf("experiment with identical v2 boost triples should be allowed: %v", err)
	}
}
