SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci;

USE hyapp_lucky_gift;

-- 生产 main 的 006 已用于 AB 实验；本迁移编号调整为 010 以保证发布目录内版本唯一。
-- 性能边界：
-- 1. 规则版本表只保存低频发布的不可变配置。生产使用双实例滚动，旧实例仍硬编码 day/72h 列，
--    因此本次只能执行 expand：补齐 old/new 四列并双向回填，绝不 CHANGE/DROP 旧列。
--    新版本仓储会双写两套列；确认所有旧实例与回滚窗口都结束后，才能用独立 contract migration 删除影子列。
--    所有加列显式要求 ALGORITHM=INSTANT，若目标 MySQL 不支持则直接失败，禁止退化为整表 COPY。
-- 2. lucky_rtp_windows 是热状态表。三个常量默认列分别使用即时 DDL，不回写历史行；每条 ALTER 仍需短暂 MDL，
--    上线前应确认没有长事务占用该表，否则迁移会等待元数据锁，但不会扫描 lucky_draw_records 等明细大表。
-- 3. lucky_user_rtp_windows 是全新空表，主键与待资格索引随建表一次完成；迁移不做历史资格回填，避免全表聚合。

-- 旧库只有 day/72h，新测试库可能只有 round/48h；逐列补齐四列，让新旧二进制在发布和回滚窗口内都能工作。
SET @has_old_column := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'lucky_gift_rule_versions' AND COLUMN_NAME = 'jackpot_user_day_rtp_max_ppm');
SET @ddl := IF(@has_old_column = 0,
  'ALTER TABLE lucky_gift_rule_versions ADD COLUMN jackpot_user_day_rtp_max_ppm BIGINT NOT NULL DEFAULT 0 COMMENT ''兼容旧实例的用户日 RTP 上限影子列；新代码与轮次列双写'' AFTER jackpot_global_rtp_max_ppm, ALGORITHM=INSTANT',
  'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;

SET @has_new_column := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'lucky_gift_rule_versions' AND COLUMN_NAME = 'jackpot_user_round_rtp_max_ppm');
SET @ddl := IF(@has_new_column = 0,
  'ALTER TABLE lucky_gift_rule_versions ADD COLUMN jackpot_user_round_rtp_max_ppm BIGINT NOT NULL DEFAULT 0 COMMENT ''动态大奖用户已结算轮次 RTP 严格上限，ppm'' AFTER jackpot_user_day_rtp_max_ppm, ALGORITHM=INSTANT',
  'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;

SET @has_old_column := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'lucky_gift_rule_versions' AND COLUMN_NAME = 'jackpot_user_day_rtp_max_ppm');
SET @has_new_column := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'lucky_gift_rule_versions' AND COLUMN_NAME = 'jackpot_user_round_rtp_max_ppm');
SET @ddl := IF(@has_old_column > 0 AND @has_new_column > 0,
  'UPDATE lucky_gift_rule_versions SET jackpot_user_round_rtp_max_ppm = jackpot_user_day_rtp_max_ppm WHERE jackpot_user_round_rtp_max_ppm = 0 AND jackpot_user_day_rtp_max_ppm <> 0', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF(@has_old_column > 0 AND @has_new_column > 0,
  'UPDATE lucky_gift_rule_versions SET jackpot_user_day_rtp_max_ppm = jackpot_user_round_rtp_max_ppm WHERE jackpot_user_day_rtp_max_ppm = 0 AND jackpot_user_round_rtp_max_ppm <> 0', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;

SET @has_old_column := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'lucky_gift_rule_versions' AND COLUMN_NAME = 'jackpot_user_72h_rtp_max_ppm');
SET @ddl := IF(@has_old_column = 0,
  'ALTER TABLE lucky_gift_rule_versions ADD COLUMN jackpot_user_72h_rtp_max_ppm BIGINT NOT NULL DEFAULT 0 COMMENT ''兼容旧实例的用户 72 小时 RTP 上限影子列；新代码与 48 小时列双写'' AFTER jackpot_user_round_rtp_max_ppm, ALGORITHM=INSTANT',
  'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;

SET @has_new_column := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'lucky_gift_rule_versions' AND COLUMN_NAME = 'jackpot_user_48h_rtp_max_ppm');
SET @ddl := IF(@has_new_column = 0,
  'ALTER TABLE lucky_gift_rule_versions ADD COLUMN jackpot_user_48h_rtp_max_ppm BIGINT NOT NULL DEFAULT 0 COMMENT ''动态大奖用户滚动 48 小时 RTP 严格上限，ppm'' AFTER jackpot_user_72h_rtp_max_ppm, ALGORITHM=INSTANT',
  'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;

SET @has_old_column := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'lucky_gift_rule_versions' AND COLUMN_NAME = 'jackpot_user_72h_rtp_max_ppm');
SET @has_new_column := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'lucky_gift_rule_versions' AND COLUMN_NAME = 'jackpot_user_48h_rtp_max_ppm');
SET @ddl := IF(@has_old_column > 0 AND @has_new_column > 0,
  'UPDATE lucky_gift_rule_versions SET jackpot_user_48h_rtp_max_ppm = jackpot_user_72h_rtp_max_ppm WHERE jackpot_user_48h_rtp_max_ppm = 0 AND jackpot_user_72h_rtp_max_ppm <> 0', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF(@has_old_column > 0 AND @has_new_column > 0,
  'UPDATE lucky_gift_rule_versions SET jackpot_user_72h_rtp_max_ppm = jackpot_user_48h_rtp_max_ppm WHERE jackpot_user_72h_rtp_max_ppm = 0 AND jackpot_user_48h_rtp_max_ppm <> 0', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;

-- 历史窗口无法可靠推导首笔、末笔和闭窗业务时间，因此默认 0 明确表示 unknown；新运行逻辑只对新窗口写真实 paid_at。
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'lucky_rtp_windows' AND COLUMN_NAME = 'started_at_ms') = 0,
  'ALTER TABLE lucky_rtp_windows ADD COLUMN started_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT ''本窗口首笔扣费事实时间，UTC epoch ms；0 表示历史窗口未知'', ALGORITHM=INSTANT', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;

SET @ddl := IF((SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'lucky_rtp_windows' AND COLUMN_NAME = 'last_paid_at_ms') = 0,
  'ALTER TABLE lucky_rtp_windows ADD COLUMN last_paid_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT ''本窗口末笔扣费事实时间，UTC epoch ms；0 表示历史窗口未知'', ALGORITHM=INSTANT', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;

SET @ddl := IF((SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'lucky_rtp_windows' AND COLUMN_NAME = 'closed_at_ms') = 0,
  'ALTER TABLE lucky_rtp_windows ADD COLUMN closed_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT ''达到结算流水并冻结资格的时间，UTC epoch ms；未关闭或历史未知为 0'', ALGORITHM=INSTANT', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;

-- 用户轮次行与全局窗口同版本、同 window_index 对齐。滚动 48 小时分子/分母在闭窗时冻结，
-- qualification_status 只允许业务层在 pending/attempted/ineligible/expired 间单向推进，资格不会跨规则版本复用。
CREATE TABLE IF NOT EXISTS lucky_user_rtp_windows (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
  pool_id VARCHAR(96) NOT NULL COMMENT '幸运礼物奖池 ID',
  rule_version BIGINT NOT NULL COMMENT '不可变规则版本；跨版本资格不能继承',
  window_index BIGINT NOT NULL COMMENT '对应全局 RTP 结算窗口序号',
  user_id BIGINT NOT NULL COMMENT '用户 ID',
  user_registered_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '用户参与本轮时由用户 owner 固化的账号创建时间；缺失时资格关闭',
  wager_coins BIGINT NOT NULL DEFAULT 0 COMMENT '用户在本结算轮次的总消耗金币',
  payout_coins BIGINT NOT NULL DEFAULT 0 COMMENT '用户在本结算轮次的总返奖金币',
  rolling_48h_wager_coins BIGINT NOT NULL DEFAULT 0 COMMENT '闭窗时最近 48 小时总消耗快照',
  rolling_48h_payout_coins BIGINT NOT NULL DEFAULT 0 COMMENT '闭窗时最近 48 小时总返奖快照',
  qualification_status VARCHAR(16) NOT NULL DEFAULT 'pending' COMMENT 'pending/attempted/ineligible/expired',
  attempted_draw_id VARCHAR(128) NOT NULL DEFAULT '' COMMENT '消费本轮资格的下一次子抽 ID；未尝试为空',
  evaluated_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '本轮资格判定或消费时间，UTC epoch ms',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  updated_at_ms BIGINT NOT NULL COMMENT '更新时间，UTC epoch ms',
  PRIMARY KEY (app_code, pool_id, rule_version, window_index, user_id),
  KEY idx_lucky_user_rtp_windows_pending (app_code, pool_id, rule_version, user_id, qualification_status, window_index)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户按全局结算轮次聚合的 RTP 与一次性大奖资格';

-- 兼容极少数曾提前创建初版用户轮次表的环境；正式 CREATE 已包含这些列，正常路径均为空操作。
SET @ddl := IF((SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'lucky_user_rtp_windows' AND COLUMN_NAME = 'user_registered_at_ms') = 0,
  'ALTER TABLE lucky_user_rtp_windows ADD COLUMN user_registered_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT ''用户参与本轮时由用户 owner 固化的账号创建时间；缺失时资格关闭'', ALGORITHM=INSTANT', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;

SET @ddl := IF((SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'lucky_user_rtp_windows' AND COLUMN_NAME = 'rolling_48h_wager_coins') = 0,
  'ALTER TABLE lucky_user_rtp_windows ADD COLUMN rolling_48h_wager_coins BIGINT NOT NULL DEFAULT 0 COMMENT ''闭窗时最近 48 小时总消耗快照'', ALGORITHM=INSTANT', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;

SET @ddl := IF((SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'lucky_user_rtp_windows' AND COLUMN_NAME = 'rolling_48h_payout_coins') = 0,
  'ALTER TABLE lucky_user_rtp_windows ADD COLUMN rolling_48h_payout_coins BIGINT NOT NULL DEFAULT 0 COMMENT ''闭窗时最近 48 小时总返奖快照'', ALGORITHM=INSTANT', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;

SET @ddl := IF((SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'lucky_user_rtp_windows' AND INDEX_NAME = 'idx_lucky_user_rtp_windows_pending') = 0,
  'ALTER TABLE lucky_user_rtp_windows ADD INDEX idx_lucky_user_rtp_windows_pending (app_code, pool_id, rule_version, user_id, qualification_status, window_index), ALGORITHM=INPLACE, LOCK=NONE', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
