package mysql

import "context"

// ensureActivityTemplateRuntimeTables mirrors migration 011 for explicitly enabled local/test auto-migrate.
func (r *Repository) ensureActivityTemplateRuntimeTables(ctx context.Context) error {
	statements := []string{
		`CREATE TABLE IF NOT EXISTS activity_template_runtime_versions (
  app_code VARCHAR(32) NOT NULL,
  template_id VARCHAR(96) NOT NULL,
  template_code VARCHAR(64) NOT NULL,
  version_no BIGINT NOT NULL,
  start_ms BIGINT NOT NULL,
  end_ms BIGINT NOT NULL,
  all_regions BOOLEAN NOT NULL DEFAULT FALSE,
  runtime_from_ms BIGINT NOT NULL,
  runtime_to_ms BIGINT NOT NULL DEFAULT 0,
  created_at_ms BIGINT NOT NULL,
  updated_at_ms BIGINT NOT NULL,
  PRIMARY KEY (app_code, template_id, version_no),
  KEY idx_activity_template_runtime_current (app_code, template_code, start_ms, end_ms, runtime_from_ms, runtime_to_ms),
  KEY idx_activity_template_runtime_due (app_code, end_ms, runtime_to_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='活动模版不可变运行版本启停窗口'`,
		`CREATE TABLE IF NOT EXISTS activity_template_runtime_regions (
  app_code VARCHAR(32) NOT NULL,
  template_id VARCHAR(96) NOT NULL,
  version_no BIGINT NOT NULL,
  region_id BIGINT NOT NULL,
  created_at_ms BIGINT NOT NULL,
  PRIMARY KEY (app_code, template_id, version_no, region_id),
  KEY idx_activity_template_runtime_region (app_code, region_id, template_id, version_no)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='活动模版运行版本区域快照'`,
		`CREATE TABLE IF NOT EXISTS activity_template_event_consumption (
  app_code VARCHAR(32) NOT NULL,
  source_event_id VARCHAR(128) NOT NULL,
  event_type VARCHAR(64) NOT NULL,
  template_id VARCHAR(96) NOT NULL DEFAULT '',
  template_code VARCHAR(64) NOT NULL DEFAULT '',
  version_no BIGINT NOT NULL DEFAULT 0,
  user_id BIGINT NOT NULL DEFAULT 0,
  region_id BIGINT NOT NULL DEFAULT 0,
  task_day VARCHAR(10) NOT NULL DEFAULT '',
  status VARCHAR(24) NOT NULL,
  skip_reason VARCHAR(128) NOT NULL DEFAULT '',
  occurred_at_ms BIGINT NOT NULL,
  consumed_at_ms BIGINT NOT NULL,
  PRIMARY KEY (app_code, source_event_id),
  KEY idx_activity_template_event_template (app_code, template_id, version_no, occurred_at_ms),
  KEY idx_activity_template_event_status (app_code, status, consumed_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='活动模版运行事件幂等事实'`,
		`CREATE TABLE IF NOT EXISTS activity_template_user_day_scores (
  app_code VARCHAR(32) NOT NULL,
  template_id VARCHAR(96) NOT NULL,
  template_code VARCHAR(64) NOT NULL,
  version_no BIGINT NOT NULL,
  task_day VARCHAR(10) NOT NULL,
  day_start_ms BIGINT NOT NULL,
  day_end_ms BIGINT NOT NULL,
  user_id BIGINT NOT NULL,
  score BIGINT NOT NULL DEFAULT 0,
  gift_count BIGINT NOT NULL DEFAULT 0,
  coin_amount BIGINT NOT NULL DEFAULT 0,
  first_scored_at_ms BIGINT NOT NULL,
  updated_at_ms BIGINT NOT NULL,
  PRIMARY KEY (app_code, template_id, version_no, task_day, user_id),
  KEY idx_activity_template_day_rank (app_code, template_id, version_no, task_day, score DESC, first_scored_at_ms, user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='活动模版 UTC 日榜实时分数'`,
		`CREATE TABLE IF NOT EXISTS activity_template_user_total_scores (
  app_code VARCHAR(32) NOT NULL,
  template_id VARCHAR(96) NOT NULL,
  template_code VARCHAR(64) NOT NULL,
  version_no BIGINT NOT NULL,
  user_id BIGINT NOT NULL,
  score BIGINT NOT NULL DEFAULT 0,
  gift_count BIGINT NOT NULL DEFAULT 0,
  coin_amount BIGINT NOT NULL DEFAULT 0,
  first_scored_at_ms BIGINT NOT NULL,
  updated_at_ms BIGINT NOT NULL,
  PRIMARY KEY (app_code, template_id, version_no, user_id),
  KEY idx_activity_template_total_rank (app_code, template_id, version_no, score DESC, first_scored_at_ms, user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='活动模版活动总榜实时分数'`,
		`CREATE TABLE IF NOT EXISTS activity_template_daily_visits (
  app_code VARCHAR(32) NOT NULL,
  template_id VARCHAR(96) NOT NULL,
  template_code VARCHAR(64) NOT NULL,
  version_no BIGINT NOT NULL,
  task_day VARCHAR(10) NOT NULL,
  user_id BIGINT NOT NULL,
  region_id BIGINT NOT NULL DEFAULT 0,
  command_id VARCHAR(128) NOT NULL,
  visited_at_ms BIGINT NOT NULL,
  PRIMARY KEY (app_code, template_id, version_no, task_day, user_id),
  UNIQUE KEY uk_activity_template_visit_command (app_code, command_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='活动模版 daily_visit 自然幂等事实'`,
		`CREATE TABLE IF NOT EXISTS activity_template_task_progress (
  app_code VARCHAR(32) NOT NULL,
  template_id VARCHAR(96) NOT NULL,
  template_code VARCHAR(64) NOT NULL,
  version_no BIGINT NOT NULL,
  task_day VARCHAR(10) NOT NULL,
  user_id BIGINT NOT NULL,
  first_region_id BIGINT NOT NULL DEFAULT 0,
  task_key VARCHAR(64) NOT NULL,
  task_type VARCHAR(32) NOT NULL,
  target_value BIGINT NOT NULL,
  progress_value BIGINT NOT NULL DEFAULT 0,
  reward_resource_group_id BIGINT NOT NULL,
  reward_snapshot_id VARCHAR(96) NOT NULL DEFAULT '',
  reward_snapshot_json JSON NULL,
  sort_order INT NOT NULL DEFAULT 0,
  status VARCHAR(24) NOT NULL,
  completed_at_ms BIGINT NOT NULL DEFAULT 0,
  earning_region_id BIGINT NOT NULL DEFAULT 0,
  attribution_at_ms BIGINT NOT NULL DEFAULT 0,
  claimed_at_ms BIGINT NOT NULL DEFAULT 0,
  updated_at_ms BIGINT NOT NULL,
  PRIMARY KEY (app_code, template_id, version_no, task_day, user_id, task_key),
  KEY idx_activity_template_task_data (app_code, template_id, version_no, task_day, task_key, status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='活动模版用户每日任务进度'`,
		`CREATE TABLE IF NOT EXISTS activity_template_task_claims (
  app_code VARCHAR(32) NOT NULL,
  claim_id VARCHAR(96) NOT NULL,
  command_id VARCHAR(128) NOT NULL,
  template_id VARCHAR(96) NOT NULL,
  template_code VARCHAR(64) NOT NULL,
  version_no BIGINT NOT NULL,
  task_day VARCHAR(10) NOT NULL,
  task_key VARCHAR(64) NOT NULL,
  user_id BIGINT NOT NULL,
  earning_region_id BIGINT NOT NULL DEFAULT 0,
  attribution_at_ms BIGINT NOT NULL DEFAULT 0,
  reward_resource_group_id BIGINT NOT NULL,
  reward_snapshot_id VARCHAR(96) NOT NULL DEFAULT '',
  reward_snapshot_json JSON NULL,
  wallet_command_id VARCHAR(160) NOT NULL,
  wallet_grant_id VARCHAR(96) NOT NULL DEFAULT '',
  status VARCHAR(24) NOT NULL,
  failure_reason VARCHAR(512) NOT NULL DEFAULT '',
  attempt_count INT NOT NULL DEFAULT 0,
  created_at_ms BIGINT NOT NULL,
  updated_at_ms BIGINT NOT NULL,
  granted_at_ms BIGINT NOT NULL DEFAULT 0,
  PRIMARY KEY (app_code, claim_id),
  UNIQUE KEY uk_activity_template_claim_command (app_code, command_id),
  UNIQUE KEY uk_activity_template_claim_task (app_code, template_id, version_no, task_day, user_id, task_key),
  UNIQUE KEY uk_activity_template_claim_wallet (app_code, wallet_command_id),
  KEY idx_activity_template_claim_status (app_code, status, updated_at_ms),
  KEY idx_activity_template_claim_admin (app_code, template_id, version_no, task_day, task_key, user_id, status, updated_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='活动模版任务资源组领奖事实'`,
		`CREATE TABLE IF NOT EXISTS activity_template_rank_periods (
  app_code VARCHAR(32) NOT NULL,
  template_id VARCHAR(96) NOT NULL,
  template_code VARCHAR(64) NOT NULL,
  version_no BIGINT NOT NULL,
  board_type VARCHAR(16) NOT NULL,
  period_key VARCHAR(24) NOT NULL,
  period_start_ms BIGINT NOT NULL,
  period_end_ms BIGINT NOT NULL,
  settle_after_ms BIGINT NOT NULL COMMENT '结算水位：周期结束加允许迟到窗口，UTC epoch ms',
  leaderboard_size INT NOT NULL,
  status VARCHAR(24) NOT NULL,
  locked_by VARCHAR(128) NOT NULL DEFAULT '',
  lock_until_ms BIGINT NOT NULL DEFAULT 0,
  settled_at_ms BIGINT NOT NULL DEFAULT 0,
  created_at_ms BIGINT NOT NULL,
  updated_at_ms BIGINT NOT NULL,
  PRIMARY KEY (app_code, template_id, version_no, board_type, period_key),
  KEY idx_activity_template_period_settle_due (app_code, status, settle_after_ms, lock_until_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='活动模版榜单结算周期'`,
		`CREATE TABLE IF NOT EXISTS activity_template_rank_snapshots (
  app_code VARCHAR(32) NOT NULL,
  template_id VARCHAR(96) NOT NULL,
  template_code VARCHAR(64) NOT NULL,
  version_no BIGINT NOT NULL,
  board_type VARCHAR(16) NOT NULL,
  period_key VARCHAR(24) NOT NULL,
  rank_no INT NOT NULL,
  user_id BIGINT NOT NULL,
  score BIGINT NOT NULL,
  gift_count BIGINT NOT NULL,
  coin_amount BIGINT NOT NULL,
  first_scored_at_ms BIGINT NOT NULL,
  snapshot_at_ms BIGINT NOT NULL,
  PRIMARY KEY (app_code, template_id, version_no, board_type, period_key, rank_no),
  UNIQUE KEY uk_activity_template_rank_user (app_code, template_id, version_no, board_type, period_key, user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='活动模版冻结榜单快照'`,
		`CREATE TABLE IF NOT EXISTS activity_template_reward_jobs (
  app_code VARCHAR(32) NOT NULL,
  reward_job_id VARCHAR(96) NOT NULL,
  template_id VARCHAR(96) NOT NULL,
  template_code VARCHAR(64) NOT NULL,
  version_no BIGINT NOT NULL,
  board_type VARCHAR(16) NOT NULL,
  period_key VARCHAR(24) NOT NULL,
  rank_no INT NOT NULL,
  user_id BIGINT NOT NULL,
  score BIGINT NOT NULL,
  resource_group_id BIGINT NOT NULL,
  reward_snapshot_id VARCHAR(96) NOT NULL DEFAULT '',
  reward_snapshot_json JSON NULL,
  wallet_command_id VARCHAR(192) NOT NULL,
  wallet_grant_id VARCHAR(96) NOT NULL DEFAULT '',
  status VARCHAR(24) NOT NULL,
  failure_reason VARCHAR(512) NOT NULL DEFAULT '',
  attempt_count INT NOT NULL DEFAULT 0,
  max_attempts INT NOT NULL DEFAULT 8 COMMENT '自动投递总尝试上限；dead 手工复活时只扩一轮预算',
  next_retry_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '下一次可领取时间，UTC epoch ms',
  locked_by VARCHAR(128) NOT NULL DEFAULT '' COMMENT '当前 job lease owner',
  lock_until_ms BIGINT NOT NULL DEFAULT 0 COMMENT 'job lease 过期时间，UTC epoch ms',
  created_at_ms BIGINT NOT NULL,
  updated_at_ms BIGINT NOT NULL,
  granted_at_ms BIGINT NOT NULL DEFAULT 0,
  PRIMARY KEY (app_code, reward_job_id),
  UNIQUE KEY uk_activity_template_reward_rank (app_code, template_id, version_no, board_type, period_key, rank_no),
  UNIQUE KEY uk_activity_template_reward_wallet (app_code, wallet_command_id),
  KEY idx_activity_template_reward_query (app_code, template_id, version_no, board_type, period_key, status),
  KEY idx_activity_template_reward_retry (app_code, status, updated_at_ms),
  KEY idx_activity_template_reward_claim (app_code, status, next_retry_at_ms, lock_until_ms, created_at_ms, reward_job_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='活动模版榜单奖励发放任务'`,
		`CREATE TABLE IF NOT EXISTS activity_template_stats_outbox (
  outbox_id VARCHAR(96) NOT NULL,
  app_code VARCHAR(32) NOT NULL,
  event_type VARCHAR(64) NOT NULL,
  payload BLOB NOT NULL,
  status VARCHAR(24) NOT NULL,
  retry_count INT NOT NULL DEFAULT 0,
  next_retry_at_ms BIGINT NOT NULL,
  locked_by VARCHAR(128) NOT NULL DEFAULT '',
  lock_until_ms BIGINT NOT NULL DEFAULT 0,
  last_error VARCHAR(512) NOT NULL DEFAULT '',
  created_at_ms BIGINT NOT NULL,
  updated_at_ms BIGINT NOT NULL,
  PRIMARY KEY (outbox_id),
  KEY idx_activity_template_stats_outbox_claim (status, next_retry_at_ms, lock_until_ms, created_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='活动模版统计事实 RocketMQ transactional outbox'`,
	}
	for _, statement := range statements {
		if _, err := r.db.ExecContext(ctx, statement); err != nil {
			return err
		}
	}
	rewardSnapshotColumns := []struct {
		table     string
		column    string
		statement string
	}{
		{"activity_template_task_progress", "reward_snapshot_id", `ALTER TABLE activity_template_task_progress ADD COLUMN reward_snapshot_id VARCHAR(96) NOT NULL DEFAULT '' AFTER reward_resource_group_id`},
		{"activity_template_task_progress", "reward_snapshot_json", `ALTER TABLE activity_template_task_progress ADD COLUMN reward_snapshot_json JSON NULL AFTER reward_snapshot_id`},
		{"activity_template_task_claims", "reward_snapshot_id", `ALTER TABLE activity_template_task_claims ADD COLUMN reward_snapshot_id VARCHAR(96) NOT NULL DEFAULT '' AFTER reward_resource_group_id`},
		{"activity_template_task_claims", "reward_snapshot_json", `ALTER TABLE activity_template_task_claims ADD COLUMN reward_snapshot_json JSON NULL AFTER reward_snapshot_id`},
		{"activity_template_daily_visits", "region_id", `ALTER TABLE activity_template_daily_visits ADD COLUMN region_id BIGINT NOT NULL DEFAULT 0 AFTER user_id`},
		{"activity_template_task_progress", "first_region_id", `ALTER TABLE activity_template_task_progress ADD COLUMN first_region_id BIGINT NOT NULL DEFAULT 0 AFTER user_id`},
		{"activity_template_task_progress", "earning_region_id", `ALTER TABLE activity_template_task_progress ADD COLUMN earning_region_id BIGINT NOT NULL DEFAULT 0 AFTER completed_at_ms`},
		{"activity_template_task_progress", "attribution_at_ms", `ALTER TABLE activity_template_task_progress ADD COLUMN attribution_at_ms BIGINT NOT NULL DEFAULT 0 AFTER earning_region_id`},
		{"activity_template_task_claims", "earning_region_id", `ALTER TABLE activity_template_task_claims ADD COLUMN earning_region_id BIGINT NOT NULL DEFAULT 0 AFTER user_id`},
		{"activity_template_task_claims", "attribution_at_ms", `ALTER TABLE activity_template_task_claims ADD COLUMN attribution_at_ms BIGINT NOT NULL DEFAULT 0 AFTER earning_region_id`},
		{"activity_template_reward_jobs", "reward_snapshot_id", `ALTER TABLE activity_template_reward_jobs ADD COLUMN reward_snapshot_id VARCHAR(96) NOT NULL DEFAULT '' AFTER resource_group_id`},
		{"activity_template_reward_jobs", "reward_snapshot_json", `ALTER TABLE activity_template_reward_jobs ADD COLUMN reward_snapshot_json JSON NULL AFTER reward_snapshot_id`},
		{"activity_template_reward_jobs", "max_attempts", `ALTER TABLE activity_template_reward_jobs ADD COLUMN max_attempts INT NOT NULL DEFAULT 8 COMMENT '自动投递总尝试上限；dead 手工复活时只扩一轮预算' AFTER attempt_count`},
		{"activity_template_reward_jobs", "next_retry_at_ms", `ALTER TABLE activity_template_reward_jobs ADD COLUMN next_retry_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '下一次可领取时间，UTC epoch ms' AFTER max_attempts`},
		{"activity_template_reward_jobs", "locked_by", `ALTER TABLE activity_template_reward_jobs ADD COLUMN locked_by VARCHAR(128) NOT NULL DEFAULT '' COMMENT '当前 job lease owner' AFTER next_retry_at_ms`},
		{"activity_template_reward_jobs", "lock_until_ms", `ALTER TABLE activity_template_reward_jobs ADD COLUMN lock_until_ms BIGINT NOT NULL DEFAULT 0 COMMENT 'job lease 过期时间，UTC epoch ms' AFTER locked_by`},
	}
	for _, addition := range rewardSnapshotColumns {
		exists, err := r.columnExists(ctx, addition.table, addition.column)
		if err != nil {
			return err
		}
		if !exists {
			if _, err := r.db.ExecContext(ctx, addition.statement); err != nil {
				return err
			}
		}
	}
	// 旧环境可能已经执行过 011。新增水位列先以 0 落地，再只回填缺失值；历史周期一旦
	// 物化便不随之后的配置变化漂移，保证结算审计可以复现当时的迟到容忍策略。
	settleAfterExists, err := r.columnExists(ctx, "activity_template_rank_periods", "settle_after_ms")
	if err != nil {
		return err
	}
	if !settleAfterExists {
		if _, err := r.db.ExecContext(ctx, `
			ALTER TABLE activity_template_rank_periods
			ADD COLUMN settle_after_ms BIGINT NOT NULL DEFAULT 0
			COMMENT '结算水位：周期结束加允许迟到窗口，UTC epoch ms' AFTER period_end_ms`); err != nil {
			return err
		}
	}
	if _, err := r.db.ExecContext(ctx, `
		UPDATE activity_template_rank_periods
		SET settle_after_ms = period_end_ms + ?
		WHERE settle_after_ms <= 0`, r.activityTemplateSettlementLatenessMS()); err != nil {
		return err
	}
	settleDueIndexExists, err := r.indexExists(ctx, "activity_template_rank_periods", "idx_activity_template_period_settle_due")
	if err != nil {
		return err
	}
	if !settleDueIndexExists {
		if _, err := r.db.ExecContext(ctx, `
			CREATE INDEX idx_activity_template_period_settle_due
			ON activity_template_rank_periods (app_code, status, settle_after_ms, lock_until_ms)`); err != nil {
			return err
		}
	}
	rewardClaimIndexExists, err := r.indexExists(ctx, "activity_template_reward_jobs", "idx_activity_template_reward_claim")
	if err != nil {
		return err
	}
	if !rewardClaimIndexExists {
		if _, err := r.db.ExecContext(ctx, `
			CREATE INDEX idx_activity_template_reward_claim
			ON activity_template_reward_jobs (app_code, status, next_retry_at_ms, lock_until_ms, created_at_ms, reward_job_id)`); err != nil {
			return err
		}
	}
	taskClaimAdminIndexExists, err := r.indexExists(ctx, "activity_template_task_claims", "idx_activity_template_claim_admin")
	if err != nil {
		return err
	}
	if !taskClaimAdminIndexExists {
		if _, err := r.db.ExecContext(ctx, `
			CREATE INDEX idx_activity_template_claim_admin
			ON activity_template_task_claims (app_code, template_id, version_no, task_day, task_key, user_id, status, updated_at_ms)`); err != nil {
			return err
		}
	}
	return nil
}
