SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci;


-- 使用 utf8mb4 连接字符集，保证中文注释、中文名称和 emoji 在导入时不被降级。
CREATE DATABASE IF NOT EXISTS hyapp_lucky_gift DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

USE hyapp_lucky_gift;

CREATE TABLE IF NOT EXISTS activities (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  activity_id VARCHAR(96) NOT NULL COMMENT '活动 ID',
  status VARCHAR(32) NOT NULL COMMENT '业务状态',
  updated_at_ms BIGINT NOT NULL COMMENT '更新时间，UTC epoch ms',
  PRIMARY KEY (app_code, activity_id),
  KEY idx_activities_status (app_code, status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物兼容活动实例表';

CREATE TABLE IF NOT EXISTS activity_event_consumption (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  event_id VARCHAR(96) NOT NULL COMMENT '事件幂等 ID',
  event_type VARCHAR(96) NOT NULL COMMENT '事件类型',
  source VARCHAR(64) NOT NULL COMMENT '来源',
  status VARCHAR(32) NOT NULL COMMENT '业务状态',
  failure_reason VARCHAR(255) NULL COMMENT '失败原因',
  consumed_at_ms BIGINT NULL 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, event_id),
  KEY idx_activity_event_consumption_status (app_code, status),
  KEY idx_activity_event_consumption_updated_at (app_code, updated_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='活动事件消费位点表';

CREATE TABLE IF NOT EXISTS lucky_gift_outbox (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  outbox_id VARCHAR(96) NOT NULL COMMENT '发件箱 ID',
  event_type VARCHAR(96) NOT NULL COMMENT '事件类型',
  payload BLOB NOT NULL COMMENT '业务负载快照',
  status VARCHAR(32) NOT NULL COMMENT '业务状态',
  retry_count INT NOT NULL DEFAULT 0 COMMENT '重试次数',
  next_retry_at_ms BIGINT NOT NULL COMMENT '下一次重试时间，UTC epoch ms',
  locked_by VARCHAR(128) NOT NULL DEFAULT '' COMMENT '当前锁定 worker',
  lock_until_ms BIGINT NOT NULL DEFAULT 0 COMMENT '锁过期时间，UTC epoch ms',
  last_error VARCHAR(512) NOT NULL DEFAULT '' COMMENT '最后一次失败原因',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  updated_at_ms BIGINT NOT NULL COMMENT '更新时间，UTC epoch ms',
  PRIMARY KEY (app_code, outbox_id),
  KEY idx_lucky_gift_outbox_status_retry (app_code, status, next_retry_at_ms),
  KEY idx_lucky_gift_outbox_lucky_retry (app_code, event_type, status, next_retry_at_ms, created_at_ms, outbox_id),
  KEY idx_lucky_gift_outbox_lucky_lock (app_code, event_type, status, lock_until_ms, created_at_ms, outbox_id),
  KEY idx_lucky_gift_outbox_retention (app_code, status, updated_at_ms, outbox_id),
  KEY idx_lucky_gift_outbox_claim_retry (event_type, status, next_retry_at_ms, created_at_ms, outbox_id),
  KEY idx_lucky_gift_outbox_claim_lock (event_type, status, lock_until_ms, created_at_ms, outbox_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物 owner outbox 表';

-- Worker 的 outbox 抢占 SQL 不带 app_code（跨 App 统一补偿），老索引都以 app_code 开头无法命中，
-- 每次轮询（默认 1 秒 × 空轮询最多 6 条查询）都会全索引扫描并 filesort 整表。
-- 这两个无 app_code 前缀的索引让空轮询变成零行索引定位，是线上 MySQL 基线 CPU 的主要治理点。
SET @ddl := IF(
  (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'lucky_gift_outbox' AND INDEX_NAME = 'idx_lucky_gift_outbox_claim_retry') = 0,
  'ALTER TABLE lucky_gift_outbox ADD INDEX idx_lucky_gift_outbox_claim_retry (event_type, status, next_retry_at_ms, created_at_ms, outbox_id), ALGORITHM=INPLACE, LOCK=NONE',
  '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_gift_outbox' AND INDEX_NAME = 'idx_lucky_gift_outbox_claim_lock') = 0,
  'ALTER TABLE lucky_gift_outbox ADD INDEX idx_lucky_gift_outbox_claim_lock (event_type, status, lock_until_ms, created_at_ms, outbox_id), ALGORITHM=INPLACE, LOCK=NONE',
  'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

CREATE TABLE IF NOT EXISTS lucky_gift_rule_versions (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
  pool_id VARCHAR(96) NOT NULL COMMENT '幸运礼物奖池 ID',
  rule_version BIGINT NOT NULL COMMENT '不可变规则版本',
  enabled TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否启用',
  strategy_version VARCHAR(32) NOT NULL DEFAULT 'fixed_v2' COMMENT 'fixed_v2/dynamic_v3；旧版本固定按 fixed_v2 解释',
  target_rtp_ppm BIGINT NOT NULL COMMENT '基础返奖目标，ppm',
  pool_rate_ppm BIGINT NOT NULL COMMENT '每笔扣费进入基础奖池比例，ppm',
  profit_rate_ppm BIGINT NOT NULL DEFAULT 0 COMMENT '每笔扣费计入平台盈利比例，ppm',
  anchor_rate_ppm BIGINT NOT NULL DEFAULT 0 COMMENT '每笔扣费计入主播收益比例，ppm',
  settlement_window_wager BIGINT NOT NULL COMMENT 'RTP 结算窗口流水，单位金币',
  control_band_ppm BIGINT NOT NULL COMMENT '正常波动带，ppm',
  gift_price_reference BIGINT NOT NULL COMMENT '配置参考礼物价格',
  novice_max_equivalent_draws BIGINT NOT NULL DEFAULT 2000 COMMENT '新手阶段截止等价抽数，按累计金币/参考价格折算',
  normal_max_equivalent_draws BIGINT NOT NULL DEFAULT 20000 COMMENT '正常阶段截止等价抽数，超过后进入高阶阶段',
  effective_from_ms BIGINT NOT NULL COMMENT '生效时间，UTC epoch ms',
  created_by_admin_id BIGINT NOT NULL DEFAULT 0 COMMENT '发布人',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  initial_pool_coins BIGINT NOT NULL DEFAULT 0 COMMENT 'dynamic_v3 奖池首次物化的初始注资金币',
  loss_streak_guarantee BIGINT NOT NULL DEFAULT 0 COMMENT '连续未中奖后的保底触发抽数',
  low_watermark_coins BIGINT NOT NULL DEFAULT 0 COMMENT '低水位阈值金币',
  low_water_nonzero_factor_ppm BIGINT NOT NULL DEFAULT 0 COMMENT '低水位非零奖档概率因子，ppm',
  high_watermark_coins BIGINT NOT NULL DEFAULT 0 COMMENT '高水位阈值金币',
  high_water_nonzero_factor_ppm BIGINT NOT NULL DEFAULT 0 COMMENT '高水位非零奖档概率因子，ppm',
  v2_high_water_boost_threshold_coins BIGINT NOT NULL DEFAULT 0 COMMENT 'fixed_v2 高水位返奖加权触发阈值金币；0表示关闭',
  v2_high_water_boost_factor_ppm BIGINT NOT NULL DEFAULT 0 COMMENT 'fixed_v2 高水位返奖加权系数，ppm；1500000表示RTP放大到150%',
  v2_high_water_boost_recover_coins BIGINT NOT NULL DEFAULT 0 COMMENT 'fixed_v2 高水位加权恢复水位金币；水位低于该值退出加权',
  recharge_boost_window_ms BIGINT NOT NULL DEFAULT 0 COMMENT '最近充值概率加权窗口，毫秒',
  recharge_boost_factor_ppm BIGINT NOT NULL DEFAULT 0 COMMENT '最近充值非零奖档概率因子，ppm',
  user_24h_rtp_threshold_ppm BIGINT NOT NULL DEFAULT 0 COMMENT '用户滚动24小时RTP降权触发线，ppm；0表示关闭',
  user_24h_ordinary_win_factor_ppm BIGINT NOT NULL DEFAULT 1000000 COMMENT '触发后普通非零奖档保留权重，ppm；1000000表示不降权',
  jackpot_multiplier_ppms JSON NOT NULL DEFAULT (JSON_ARRAY()) COMMENT '动态大奖倍率列表，1x=1000000',
  jackpot_global_rtp_max_ppm BIGINT NOT NULL DEFAULT 0 COMMENT '动态大奖全局 RTP 上限，ppm',
  jackpot_user_day_rtp_max_ppm BIGINT NOT NULL DEFAULT 0 COMMENT '兼容旧实例的用户日 RTP 上限影子列；新代码与轮次列双写',
  jackpot_user_round_rtp_max_ppm BIGINT NOT NULL DEFAULT 0 COMMENT '动态大奖用户已结算轮次 RTP 严格上限，ppm',
  jackpot_user_72h_rtp_max_ppm BIGINT NOT NULL DEFAULT 0 COMMENT '兼容旧实例的用户 72 小时 RTP 上限影子列；新代码与 48 小时列双写',
  jackpot_user_48h_rtp_max_ppm BIGINT NOT NULL DEFAULT 0 COMMENT '动态大奖用户滚动 48 小时 RTP 严格上限，ppm',
  jackpot_spend_threshold_coins BIGINT NOT NULL DEFAULT 0 COMMENT '规则版本动态配置的用户 UTC 日累计消费大奖门槛金币',
  max_jackpot_hits_per_user_day BIGINT NOT NULL DEFAULT 0 COMMENT '单用户 UTC 日动态大奖命中上限',
  jackpot_rate_limit_window_minutes BIGINT NOT NULL DEFAULT 0 COMMENT 'app+pool 全局滚动爆奖窗口分钟数；0仅兼容历史规则',
  max_jackpot_hits_per_window BIGINT NOT NULL DEFAULT 0 COMMENT '全局滚动窗口内两类大奖合计上限；0仅兼容历史规则',
  max_single_payout BIGINT NOT NULL DEFAULT 0 COMMENT '单次返奖金币上限',
  user_hourly_payout_cap BIGINT NOT NULL DEFAULT 0 COMMENT '单用户 UTC 小时返奖上限',
  user_daily_payout_cap BIGINT NOT NULL DEFAULT 0 COMMENT '单用户 UTC 日返奖上限',
  device_daily_payout_cap BIGINT NOT NULL DEFAULT 0 COMMENT '单设备 UTC 日返奖上限',
  room_hourly_payout_cap BIGINT NOT NULL DEFAULT 0 COMMENT '单房间 UTC 小时返奖上限',
  anchor_daily_payout_cap BIGINT NOT NULL DEFAULT 0 COMMENT '单主播 UTC 日返奖上限',
  PRIMARY KEY (app_code, pool_id, rule_version),
  KEY idx_lucky_gift_rule_versions_latest (app_code, pool_id, rule_version),
  KEY idx_lucky_gift_rule_versions_enabled (app_code, enabled, created_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物 v2 规则版本表';

CREATE TABLE IF NOT EXISTS lucky_gift_stage_tiers (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
  pool_id VARCHAR(96) NOT NULL COMMENT '幸运礼物奖池 ID',
  rule_version BIGINT NOT NULL COMMENT '规则版本',
  stage VARCHAR(32) NOT NULL COMMENT 'novice/normal/advanced',
  min_recharge_7d_coins BIGINT NOT NULL DEFAULT 0 COMMENT 'normal/advanced 最近 7 日充值下限；novice 的 0 仅为 sentinel',
  min_recharge_30d_coins BIGINT NOT NULL DEFAULT 0 COMMENT 'normal/advanced 最近 30 日充值下限；novice 的 0 仅为 sentinel',
  tier_id VARCHAR(96) NOT NULL COMMENT '奖档 ID',
  multiplier_ppm BIGINT NOT NULL COMMENT '倍率，1x = 1000000',
  base_weight_ppm BIGINT NOT NULL COMMENT '正常模式基础概率，ppm',
  high_water_only TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否高水位才开放',
  enabled TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
  PRIMARY KEY (app_code, pool_id, rule_version, stage, tier_id),
  KEY idx_lucky_gift_stage_tiers_stage (app_code, pool_id, rule_version, stage)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物 v2 阶段奖档表';

CREATE TABLE IF NOT EXISTS lucky_rtp_windows (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
  scope_type VARCHAR(32) NOT NULL COMMENT 'global 或 gift',
  scope_id VARCHAR(128) NOT NULL COMMENT '奖池+不可变规则版本作用域',
  window_index BIGINT NOT NULL COMMENT 'RTP 窗口序号',
  target_rtp_ppm INT NOT NULL COMMENT '窗口目标 RTP',
  control_window_draws BIGINT NOT NULL COMMENT 'fixed_v2窗口抽数；dynamic_v3仅兼容展示，滚窗读取规则真实流水阈值',
  paid_draws BIGINT NOT NULL DEFAULT 0 COMMENT '窗口已抽次数',
  wager_coins BIGINT NOT NULL DEFAULT 0 COMMENT '窗口消耗金币',
  target_payout_coins BIGINT NOT NULL COMMENT '窗口目标基础返奖',
  actual_base_payout_coins BIGINT NOT NULL DEFAULT 0 COMMENT '窗口实际基础返奖',
  carry_ppm BIGINT NOT NULL DEFAULT 0 COMMENT '整数除法余数',
  status VARCHAR(32) NOT NULL DEFAULT 'open' COMMENT 'open/closed/underpaid',
  started_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '本窗口首笔扣费事实时间，UTC epoch ms；0 表示历史窗口未知',
  last_paid_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '本窗口末笔扣费事实时间，UTC epoch ms；0 表示历史窗口未知',
  closed_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '达到结算流水并冻结资格的时间，UTC epoch ms；未关闭或历史未知为 0',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  updated_at_ms BIGINT NOT NULL COMMENT '更新时间，UTC epoch ms',
  PRIMARY KEY (app_code, scope_type, scope_id, window_index),
  KEY idx_lucky_rtp_windows_open (app_code, scope_type, scope_id, status, window_index)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物 RTP 控制窗口';

-- 每个用户在每个全局结算轮次只保留一行聚合与一次性资格状态。滚动 48 小时合计在闭窗时冻结，
-- 后续同毫秒子抽或延迟使用资格都读取该快照，不会被闭窗后的新事实反向污染。
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 TABLE IF NOT EXISTS lucky_pools (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
  scope_type VARCHAR(32) NOT NULL COMMENT 'pool',
  scope_id VARCHAR(96) NOT NULL COMMENT '幸运礼物奖池 ID',
  balance BIGINT NOT NULL DEFAULT 0 COMMENT '当前可用水位',
  reserve_floor BIGINT NOT NULL DEFAULT 0 COMMENT '安全水位',
  total_in BIGINT NOT NULL DEFAULT 0 COMMENT '累计入池',
  total_out BIGINT NOT NULL DEFAULT 0 COMMENT '累计基础返奖支出',
  manual_credit_total BIGINT NOT NULL DEFAULT 0 COMMENT '累计人工注资金币，不计入业务 total_in',
  manual_debit_total BIGINT NOT NULL DEFAULT 0 COMMENT '累计人工扣资金币，不计入业务 total_out',
  v2_boost_active TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'fixed_v2 高水位返奖加权滞回标志；1表示当前处于加权区间',
  profit_total BIGINT NOT NULL DEFAULT 0 COMMENT 'dynamic_v3 累计平台盈利拆账金币',
  anchor_income_total BIGINT NOT NULL DEFAULT 0 COMMENT 'dynamic_v3 累计主播收益拆账金币',
  initial_seed_total BIGINT NOT NULL DEFAULT 0 COMMENT 'dynamic_v3 累计初始注资金币，只在首次物化时增加',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  updated_at_ms BIGINT NOT NULL COMMENT '更新时间，UTC epoch ms',
  PRIMARY KEY (app_code, scope_type, scope_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物单一基础奖池';

CREATE TABLE IF NOT EXISTS lucky_pool_adjustments (
  app_code VARCHAR(32) NOT NULL COMMENT '应用编码',
  adjustment_id VARCHAR(128) NOT NULL COMMENT '调用方资金幂等 ID',
  pool_id VARCHAR(96) NOT NULL COMMENT '幸运礼物奖池 ID',
  strategy_version VARCHAR(32) NOT NULL COMMENT 'fixed_v2/dynamic_v3',
  scope_type VARCHAR(32) NOT NULL COMMENT '实际资金账本 scope_type',
  direction VARCHAR(16) NOT NULL COMMENT 'in/out',
  amount_coins BIGINT NOT NULL COMMENT '本次人工调整金币',
  reason VARCHAR(512) NOT NULL COMMENT '管理员填写的调整原因',
  operator_admin_id BIGINT NOT NULL COMMENT '操作管理员 ID',
  request_id VARCHAR(128) NOT NULL DEFAULT '' COMMENT '链路 request_id，不作为幂等键',
  insert_token VARCHAR(64) NOT NULL COMMENT '首次插入事务随机令牌，用于并发幂等判定',
  balance_before BIGINT NOT NULL DEFAULT 0 COMMENT '首次应用前余额',
  balance_after BIGINT NOT NULL DEFAULT 0 COMMENT '首次应用后余额',
  pool_snapshot_json JSON NULL COMMENT '首次应用后的完整奖池快照，供幂等重放',
  status VARCHAR(16) NOT NULL DEFAULT 'pending' COMMENT 'pending/applied',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  updated_at_ms BIGINT NOT NULL COMMENT '更新时间，UTC epoch ms',
  PRIMARY KEY (app_code, adjustment_id),
  KEY idx_lucky_pool_adjustments_pool (app_code, pool_id, strategy_version, created_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物人工奖池调整事实';

CREATE TABLE IF NOT EXISTS lucky_risk_counters (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
  scope_type VARCHAR(32) NOT NULL COMMENT 'user/device/room/anchor',
  scope_id VARCHAR(255) NOT NULL COMMENT 'pool_id+风控主体 ID；容纳96字符奖池与128字符设备',
  window_type VARCHAR(32) NOT NULL COMMENT 'hour/day',
  bucket_key VARCHAR(32) NOT NULL COMMENT 'UTC 窗口键',
  payout_coins BIGINT NOT NULL DEFAULT 0 COMMENT '窗口内已支出可见奖励',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  updated_at_ms BIGINT NOT NULL COMMENT '更新时间，UTC epoch ms',
  PRIMARY KEY (app_code, scope_type, scope_id, window_type, bucket_key)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物多维风控窗口计数';

CREATE TABLE IF NOT EXISTS lucky_user_rtp_hour_buckets (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
  pool_id VARCHAR(96) NOT NULL COMMENT '幸运礼物奖池 ID',
  user_id BIGINT NOT NULL COMMENT '用户 ID',
  bucket_hour_ms BIGINT NOT NULL COMMENT 'UTC 小时开始时间，epoch ms',
  wager_coins BIGINT NOT NULL DEFAULT 0 COMMENT '小时内抽奖流水金币',
  payout_coins BIGINT NOT NULL DEFAULT 0 COMMENT '小时内返奖金币',
  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, user_id, bucket_hour_ms),
  KEY idx_lucky_user_rtp_hour_retention (app_code, bucket_hour_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户滚动48小时RTP完整小时聚合桶';

-- 小时桶负责完整小时；closed_at_ms 保存实际末笔支付毫秒，查询用 [closed_at+1ms-48h,closed_at+1ms)
-- 纳入触发结算的末笔事实，边界事件只补齐两端不足一小时的片段。
-- 这样闭窗热路径最多扫描 47 个完整小时桶和两个边界小时内的用户事件，不回扫全量抽奖事实。
CREATE TABLE IF NOT EXISTS lucky_user_rtp_boundary_events (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
  pool_id VARCHAR(96) NOT NULL COMMENT '幸运礼物奖池 ID',
  user_id BIGINT NOT NULL COMMENT '用户 ID',
  draw_id VARCHAR(128) NOT NULL COMMENT '单抽事实 ID，用于幂等',
  occurred_at_ms BIGINT NOT NULL COMMENT '扣费事实时间，UTC epoch ms',
  wager_coins BIGINT NOT NULL COMMENT '本抽流水金币',
  payout_coins BIGINT NOT NULL COMMENT '本抽已承诺返奖负债',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  PRIMARY KEY (app_code, pool_id, user_id, draw_id),
  KEY idx_lucky_user_rtp_boundary_range (app_code, pool_id, user_id, occurred_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户严格滚动48小时RTP边界事件';

CREATE TABLE IF NOT EXISTS lucky_user_strategy_days (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
  pool_id VARCHAR(96) NOT NULL COMMENT '幸运礼物奖池 ID',
  user_id BIGINT NOT NULL COMMENT '用户 ID',
  stat_day DATE NOT NULL COMMENT 'UTC 自然日',
  wager_coins BIGINT NOT NULL DEFAULT 0 COMMENT '当日抽奖流水金币',
  payout_coins BIGINT NOT NULL DEFAULT 0 COMMENT '当日返奖金币',
  spend_coins BIGINT NOT NULL DEFAULT 0 COMMENT '当日用于动态大奖资格的累计消费金币',
  spend_rule_version BIGINT NOT NULL DEFAULT 0 COMMENT 'spend_coins 所属不可变规则版本；切换版本时从0重新累计',
  jackpot_hits BIGINT NOT NULL DEFAULT 0 COMMENT '当日动态大奖已命中次数',
  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, user_id, stat_day),
  KEY idx_lucky_user_strategy_days_retention (app_code, stat_day)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户 dynamic_v3 UTC 日级消费、RTP 与大奖资格状态';

CREATE TABLE IF NOT EXISTS lucky_user_states (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
  user_id BIGINT NOT NULL COMMENT '用户 ID',
  gift_id VARCHAR(96) NOT NULL COMMENT '奖池 ID；当前列名沿用旧内部作用域名',
  paid_draws BIGINT NOT NULL DEFAULT 0 COMMENT '该用户幸运礼物累计付费抽数',
  cumulative_wager_coins BIGINT NOT NULL DEFAULT 0 COMMENT '该用户在当前奖池累计消耗金币',
  equivalent_draws BIGINT NOT NULL DEFAULT 0 COMMENT '累计金币按规则参考价格折算后的等价抽数',
  loss_streak BIGINT NOT NULL DEFAULT 0 COMMENT '连续未获得可见奖励次数，中奖后清零',
  pending_jackpot_tokens BIGINT NOT NULL DEFAULT 0 COMMENT '旧版消费资格；新版运行时仅惰性清零，永不参与开奖',
  pending_spend_jackpot_tokens BIGINT NOT NULL DEFAULT 0 COMMENT '新版累计消费大奖资格；受阻时跨轮次和UTC日保留，成功开奖仅扣1',
  pending_spend_jackpot_rule_version BIGINT NOT NULL DEFAULT 0 COMMENT '消费大奖资格所属不可变规则版本；0及版本不匹配均在下一抽安全过期',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  updated_at_ms BIGINT NOT NULL COMMENT '更新时间，UTC epoch ms',
  PRIMARY KEY (app_code, user_id, gift_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物用户体验池状态';

-- draw 事实不存在时 SELECT ... FOR UPDATE 没有可锁记录；该锁行保证同一钱包 command_id 的
-- 首次并发请求串行执行，等待者在首事务提交后只回读原始结果，不重新随机或重复推进奖池。
CREATE TABLE IF NOT EXISTS lucky_gift_command_locks (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
  command_id VARCHAR(128) NOT NULL COMMENT '钱包已扣费命令幂等 ID',
  created_at_ms BIGINT NOT NULL COMMENT '首次请求时间，UTC epoch ms',
  PRIMARY KEY (app_code, command_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='内部幸运礼物并发幂等锁行';

CREATE TABLE IF NOT EXISTS lucky_draw_records (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
  draw_id VARCHAR(128) NOT NULL COMMENT '抽奖 ID',
  command_id VARCHAR(128) NOT NULL COMMENT '幂等命令 ID',
  user_id BIGINT NOT NULL COMMENT '用户 ID',
  device_id VARCHAR(128) NOT NULL COMMENT '设备 ID',
  room_id VARCHAR(96) NOT NULL COMMENT '房间 ID',
  anchor_id VARCHAR(96) NOT NULL COMMENT '主播关联 ID',
  visible_region_id BIGINT NOT NULL DEFAULT 0 COMMENT '房间可见区域 ID',
  pool_id VARCHAR(96) NOT NULL COMMENT '幸运礼物奖池 ID',
  gift_id VARCHAR(96) NOT NULL COMMENT '礼物 ID',
  coin_spent BIGINT NOT NULL COMMENT '消耗金币',
  rule_version BIGINT NOT NULL COMMENT '规则版本',
  experience_pool VARCHAR(32) NOT NULL COMMENT '体验池',
  rtp_window_index BIGINT NOT NULL COMMENT '全站 RTP 窗口',
  gift_rtp_window_index BIGINT NOT NULL COMMENT '礼物 RTP 窗口',
  selected_tier_id VARCHAR(96) NOT NULL COMMENT '命中奖档',
  base_reward_coins BIGINT NOT NULL DEFAULT 0 COMMENT '基础 RTP 返奖',
  effective_reward_coins BIGINT NOT NULL DEFAULT 0 COMMENT '用户可见总奖励',
  stage_feedback TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否阶段反馈',
  high_multiplier TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否高倍命中',
  candidate_tiers_json JSON NOT NULL COMMENT '候选过滤快照',
  pool_snapshot_json JSON NOT NULL COMMENT '奖池快照',
  rtp_snapshot_json JSON NOT NULL COMMENT 'RTP 快照',
  reward_status VARCHAR(32) NOT NULL COMMENT 'pending/granted/failed',
  reward_transaction_id VARCHAR(128) NOT NULL DEFAULT '' COMMENT '返奖钱包交易 ID',
  reward_failure_reason VARCHAR(255) NOT NULL DEFAULT '' COMMENT '返奖失败原因',
  paid_at_ms BIGINT NOT NULL 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, draw_id),
  UNIQUE KEY uk_lucky_draw_command (app_code, command_id),
  KEY idx_lucky_draw_pool (app_code, pool_id, created_at_ms),
  KEY idx_lucky_draw_user (app_code, user_id, created_at_ms),
  KEY idx_lucky_draw_gift (app_code, gift_id, created_at_ms),
  KEY idx_lucky_draw_room (app_code, room_id, created_at_ms),
  KEY idx_lucky_draw_region_created (app_code, visible_region_id, created_at_ms, draw_id),
  KEY idx_lucky_draw_status (app_code, reward_status, updated_at_ms),
  KEY idx_lucky_draw_created (app_code, created_at_ms, draw_id),
  KEY idx_lucky_draw_pool_status_summary (app_code, pool_id, reward_status, created_at_ms, draw_id),
  KEY idx_lucky_draw_gift_status_summary (app_code, pool_id, gift_id, reward_status, created_at_ms, draw_id),
  KEY idx_lucky_draw_pool_version (app_code, pool_id, rule_version, created_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物抽奖事实';

CREATE TABLE IF NOT EXISTS lucky_draw_pool_stats (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
  pool_id VARCHAR(96) NOT NULL COMMENT '幸运礼物奖池 ID',
  gift_id VARCHAR(96) NOT NULL DEFAULT '' COMMENT '礼物 ID，空值表示奖池汇总',
  total_draws BIGINT NOT NULL DEFAULT 0 COMMENT '抽奖次数',
  unique_users BIGINT NOT NULL DEFAULT 0 COMMENT '参与用户数',
  unique_rooms BIGINT NOT NULL DEFAULT 0 COMMENT '参与房间数',
  total_spent_coins BIGINT NOT NULL DEFAULT 0 COMMENT '消耗金币',
  total_reward_coins BIGINT NOT NULL DEFAULT 0 COMMENT '返还金币',
  base_reward_coins BIGINT NOT NULL DEFAULT 0 COMMENT '基础 RTP 返奖',
  pending_draws BIGINT NOT NULL DEFAULT 0 COMMENT '待发放数量',
  granted_draws BIGINT NOT NULL DEFAULT 0 COMMENT '已发放数量',
  failed_draws BIGINT NOT NULL DEFAULT 0 COMMENT '发放失败数量',
  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, gift_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物池级汇总统计';

CREATE TABLE IF NOT EXISTS lucky_draw_pool_day_stats (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
  stat_day DATE NOT NULL COMMENT '北京日（+08:00），与 statistics-service 社交 BI 的分日口径一致',
  visible_region_id BIGINT NOT NULL DEFAULT 0 COMMENT '房间可见区域 ID',
  pool_id VARCHAR(96) NOT NULL COMMENT '幸运礼物奖池 ID',
  gift_id VARCHAR(96) NOT NULL DEFAULT '' COMMENT '礼物 ID，空值表示奖池汇总',
  strategy_version VARCHAR(32) NOT NULL DEFAULT 'fixed_v2' COMMENT '策略族 fixed_v2/dynamic_v3；AB 实验下同池同日会双行，BI 按策略过滤',
  draw_count BIGINT NOT NULL DEFAULT 0 COMMENT '抽奖次数',
  turnover_coin BIGINT NOT NULL DEFAULT 0 COMMENT '消耗金币',
  payout_coin BIGINT NOT NULL DEFAULT 0 COMMENT '用户可见返奖金币',
  base_reward_coin BIGINT NOT NULL DEFAULT 0 COMMENT '基础 RTP 返奖',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  updated_at_ms BIGINT NOT NULL COMMENT '更新时间，UTC epoch ms',
  PRIMARY KEY (app_code, stat_day, visible_region_id, pool_id, gift_id, strategy_version),
  KEY idx_lucky_draw_pool_day_overview (app_code, stat_day, pool_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物 Databi 日维度汇总';

CREATE TABLE IF NOT EXISTS lucky_draw_pool_stat_users (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
  pool_id VARCHAR(96) NOT NULL COMMENT '幸运礼物奖池 ID',
  gift_id VARCHAR(96) NOT NULL DEFAULT '' COMMENT '礼物 ID，空值表示奖池汇总',
  user_id BIGINT NOT NULL COMMENT '用户 ID',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  PRIMARY KEY (app_code, pool_id, gift_id, user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物汇总用户去重';

CREATE TABLE IF NOT EXISTS lucky_draw_pool_stat_rooms (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
  pool_id VARCHAR(96) NOT NULL COMMENT '幸运礼物奖池 ID',
  gift_id VARCHAR(96) NOT NULL DEFAULT '' COMMENT '礼物 ID，空值表示奖池汇总',
  room_id VARCHAR(96) NOT NULL COMMENT '房间 ID',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  PRIMARY KEY (app_code, pool_id, gift_id, room_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物汇总房间去重';

CREATE TABLE IF NOT EXISTS lucky_draw_pool_stat_cursors (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码',
  cursor_name VARCHAR(64) NOT NULL COMMENT '游标名称',
  last_draw_created_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '最后已聚合 draw 创建时间',
  last_draw_id VARCHAR(128) NOT NULL DEFAULT '' COMMENT '同一毫秒内最后已聚合 draw ID',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  updated_at_ms BIGINT NOT NULL COMMENT '更新时间，UTC epoch ms',
  PRIMARY KEY (app_code, cursor_name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物后台统计快照游标';

CREATE TABLE IF NOT EXISTS lucky_gift_user_profiles (
  app_code VARCHAR(32) NOT NULL COMMENT '应用编码',
  pool_id VARCHAR(96) NOT NULL COMMENT '幸运礼物奖池 ID',
  strategy_version VARCHAR(32) NOT NULL COMMENT 'fixed_v2/dynamic_v3；两套奖池画像严格隔离',
  identity_type VARCHAR(16) NOT NULL COMMENT 'internal/external',
  identity_key VARCHAR(128) COLLATE utf8mb4_bin NOT NULL COMMENT '内部 user_id 文本或外部 external_user_id',
  strategy_user_id BIGINT NOT NULL COMMENT '仅供本服务关联策略状态，绝不下发',
  internal_user_id BIGINT NOT NULL DEFAULT 0 COMMENT '内部真实 user_id',
  external_user_id VARCHAR(128) COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT '外部原始用户 ID',
  rule_version BIGINT NOT NULL DEFAULT 0 COMMENT '最近规则版本',
  current_stage VARCHAR(32) NOT NULL DEFAULT '' COMMENT '最近阶段',
  total_draws BIGINT NOT NULL DEFAULT 0 COMMENT '累计子抽次数',
  total_wager_coins BIGINT NOT NULL DEFAULT 0 COMMENT '累计消耗金币',
  total_payout_coins BIGINT NOT NULL DEFAULT 0 COMMENT '累计返奖金币',
  lifetime_rtp_ppm BIGINT NOT NULL DEFAULT 0 COMMENT '累计 RTP，物化后用于无 filesort 游标排序',
  total_base_reward_coins BIGINT NOT NULL DEFAULT 0 COMMENT '累计基础返奖',
  ordinary_win_count BIGINT NOT NULL DEFAULT 0 COMMENT '普通非零奖次数',
  high_multiplier_ordinary_win_count BIGINT NOT NULL DEFAULT 0 COMMENT '高倍率普通奖次数',
  rtp_compensation_jackpot_count BIGINT NOT NULL DEFAULT 0 COMMENT 'RTP 补偿大奖次数',
  cumulative_spend_jackpot_count BIGINT NOT NULL DEFAULT 0 COMMENT '累计消费大奖次数',
  jackpot_count BIGINT NOT NULL DEFAULT 0 COMMENT '两类独立大奖累计次数，物化后用于排序和筛选',
  guarantee_hit_count BIGINT NOT NULL DEFAULT 0 COMMENT '连续未中保护命中次数',
  zero_draw_count BIGINT NOT NULL DEFAULT 0 COMMENT '未中奖次数',
  granted_draw_count BIGINT NOT NULL DEFAULT 0 COMMENT '已发放次数',
  pending_draw_count BIGINT NOT NULL DEFAULT 0 COMMENT '待发放次数',
  failed_draw_count BIGINT NOT NULL DEFAULT 0 COMMENT '发放失败次数',
  max_multiplier_ppm BIGINT NOT NULL DEFAULT 0 COMMENT '最高倍率',
  max_reward_coins BIGINT NOT NULL DEFAULT 0 COMMENT '最高单抽返奖',
  last_downweight_active TINYINT(1) NOT NULL DEFAULT 0 COMMENT '最近是否触发 24h RTP 降权',
  current_equivalent_draws BIGINT NOT NULL DEFAULT 0 COMMENT '当前运行状态的等价抽数快照',
  current_loss_streak BIGINT NOT NULL DEFAULT 0 COMMENT '当前连续未中奖次数快照',
  current_pending_spend_jackpot_tokens BIGINT NOT NULL DEFAULT 0 COMMENT '当前累计消费大奖资格快照',
  first_draw_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '首次抽奖时间',
  last_draw_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '最近抽奖时间',
  aggregated_at_ms BIGINT NOT NULL COMMENT '最近聚合时间',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间',
  updated_at_ms BIGINT NOT NULL COMMENT '更新时间',
  PRIMARY KEY (app_code, pool_id, strategy_version, identity_type, identity_key),
  KEY idx_lucky_user_profile_sort_last (app_code, pool_id, strategy_version, last_draw_at_ms DESC, identity_type DESC, identity_key DESC),
  KEY idx_lucky_user_profile_sort_rtp (app_code, pool_id, strategy_version, lifetime_rtp_ppm DESC, identity_type DESC, identity_key DESC),
  KEY idx_lucky_user_profile_sort_wager (app_code, pool_id, strategy_version, total_wager_coins DESC, identity_type DESC, identity_key DESC),
  KEY idx_lucky_user_profile_sort_payout (app_code, pool_id, strategy_version, total_payout_coins DESC, identity_type DESC, identity_key DESC),
  KEY idx_lucky_user_profile_sort_jackpot (app_code, pool_id, strategy_version, jackpot_count DESC, identity_type DESC, identity_key DESC),
  KEY idx_lucky_user_profile_sort_loss (app_code, pool_id, strategy_version, current_loss_streak DESC, identity_type DESC, identity_key DESC),
  KEY idx_lucky_user_profile_stage (app_code, pool_id, strategy_version, current_stage, identity_type, identity_key),
  KEY idx_lucky_user_profile_pending (app_code, pool_id, strategy_version, current_pending_spend_jackpot_tokens DESC, identity_type DESC, identity_key DESC),
  KEY idx_lucky_user_profile_internal (app_code, pool_id, strategy_version, internal_user_id),
  KEY idx_lucky_user_profile_external (app_code, pool_id, strategy_version, external_user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物用户画像累计快照';

CREATE TABLE IF NOT EXISTS lucky_gift_user_profile_events (
  app_code VARCHAR(32) NOT NULL COMMENT '应用编码',
  source_type VARCHAR(24) NOT NULL COMMENT 'internal/external_item/external_legacy',
  source_draw_id VARCHAR(128) NOT NULL COMMENT '来源抽奖事实 ID',
  pool_id VARCHAR(96) NOT NULL COMMENT '幸运礼物奖池 ID',
  strategy_version VARCHAR(32) NOT NULL COMMENT 'fixed_v2/dynamic_v3',
  identity_type VARCHAR(16) NOT NULL COMMENT 'internal/external',
  identity_key VARCHAR(128) COLLATE utf8mb4_bin NOT NULL COMMENT '用户身份键',
  draw_count BIGINT NOT NULL DEFAULT 1 COMMENT '代表的子抽次数；fixed_v2 外部整单固定为 1',
  wager_coins BIGINT NOT NULL DEFAULT 0 COMMENT '消耗金币',
  payout_coins BIGINT NOT NULL DEFAULT 0 COMMENT '返奖金币',
  base_reward_coins BIGINT NOT NULL DEFAULT 0 COMMENT '基础返奖',
  multiplier_ppm BIGINT NOT NULL DEFAULT 0 COMMENT '命中倍率',
  hit_type VARCHAR(32) NOT NULL COMMENT 'zero/ordinary/rtp_compensation/spend_milestone',
  reward_status VARCHAR(32) NOT NULL COMMENT 'pending/granted/failed',
  occurred_at_ms BIGINT NOT NULL COMMENT '支付事实时间',
  aggregation_token VARCHAR(96) NOT NULL DEFAULT '' COMMENT '首次插入者的聚合批次令牌',
  created_at_ms BIGINT NOT NULL COMMENT '读模型写入时间',
  PRIMARY KEY (app_code, source_type, source_draw_id),
  KEY idx_lucky_user_profile_event_window (app_code, pool_id, strategy_version, identity_type, identity_key, occurred_at_ms),
  KEY idx_lucky_user_profile_event_token (app_code, source_type, aggregation_token)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物用户画像窗口事件';

CREATE TABLE IF NOT EXISTS lucky_gift_user_multiplier_stats (
  app_code VARCHAR(32) NOT NULL COMMENT '应用编码',
  pool_id VARCHAR(96) NOT NULL COMMENT '幸运礼物奖池 ID',
  strategy_version VARCHAR(32) NOT NULL COMMENT 'fixed_v2/dynamic_v3',
  identity_type VARCHAR(16) NOT NULL COMMENT 'internal/external',
  identity_key VARCHAR(128) COLLATE utf8mb4_bin NOT NULL COMMENT '用户身份键',
  hit_type VARCHAR(32) NOT NULL COMMENT '普通奖和两类大奖独立分类',
  multiplier_ppm BIGINT NOT NULL COMMENT '倍率',
  draw_count BIGINT NOT NULL DEFAULT 0 COMMENT '命中次数',
  wager_coins BIGINT NOT NULL DEFAULT 0 COMMENT '消耗金币',
  payout_coins BIGINT NOT NULL DEFAULT 0 COMMENT '返奖金币',
  updated_at_ms BIGINT NOT NULL COMMENT '更新时间',
  PRIMARY KEY (app_code, pool_id, strategy_version, identity_type, identity_key, hit_type, multiplier_ppm)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物用户画像倍率分布';

CREATE TABLE IF NOT EXISTS lucky_gift_user_jackpot_hits (
  app_code VARCHAR(32) NOT NULL COMMENT '应用编码',
  source_type VARCHAR(24) NOT NULL COMMENT 'internal/external_item',
  source_draw_id VARCHAR(128) NOT NULL COMMENT '来源抽奖事实 ID',
  pool_id VARCHAR(96) NOT NULL COMMENT '幸运礼物奖池 ID',
  strategy_version VARCHAR(32) NOT NULL COMMENT 'fixed_v2/dynamic_v3',
  identity_type VARCHAR(16) NOT NULL COMMENT 'internal/external',
  identity_key VARCHAR(128) COLLATE utf8mb4_bin NOT NULL COMMENT '用户身份键',
  request_id VARCHAR(128) NOT NULL DEFAULT '' COMMENT '内部 command_id 或外部 request_id',
  rule_version BIGINT NOT NULL DEFAULT 0 COMMENT '规则版本',
  stage VARCHAR(32) NOT NULL DEFAULT '' COMMENT '命中时阶段',
  mechanism VARCHAR(32) NOT NULL COMMENT '大奖机制',
  reason_code VARCHAR(96) NOT NULL DEFAULT '' COMMENT '最终原因码',
  tier_id VARCHAR(96) NOT NULL DEFAULT '' COMMENT '大奖 tier ID',
  multiplier_ppm BIGINT NOT NULL DEFAULT 0 COMMENT '大奖倍率',
  wager_coins BIGINT NOT NULL DEFAULT 0 COMMENT '本抽消耗',
  payout_coins BIGINT NOT NULL DEFAULT 0 COMMENT '本抽返奖',
  conditions_json JSON NOT NULL COMMENT '大奖条件快照',
  occurred_at_ms BIGINT NOT NULL COMMENT '支付事实时间',
  created_at_ms BIGINT NOT NULL COMMENT '读模型写入时间',
  PRIMARY KEY (app_code, source_type, source_draw_id),
  KEY idx_lucky_user_jackpot_profile (app_code, pool_id, strategy_version, identity_type, identity_key, occurred_at_ms DESC, source_type DESC, source_draw_id DESC),
  KEY idx_lucky_jackpot_rate_window (app_code, pool_id, occurred_at_ms, source_type, source_draw_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物用户画像大奖解释';

CREATE TABLE IF NOT EXISTS external_lucky_gift_request_locks (
  app_code VARCHAR(32) NOT NULL COMMENT '外部 App 应用编码',
  request_id VARCHAR(128) NOT NULL COMMENT '外部业务幂等 ID',
  created_at_ms BIGINT NOT NULL COMMENT '首次请求时间，UTC epoch ms',
  PRIMARY KEY (app_code, request_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='外部幸运礼物并发幂等锁行';

CREATE TABLE IF NOT EXISTS external_lucky_gift_draws (
  app_code VARCHAR(32) NOT NULL COMMENT '外部 App 应用编码',
  request_id VARCHAR(128) NOT NULL COMMENT '外部 App 业务幂等 ID',
  draw_id VARCHAR(128) NOT NULL COMMENT 'HyApp 抽奖 ID',
  external_user_id VARCHAR(128) NOT NULL COMMENT '外部 App 用户 ID',
  pool_id VARCHAR(96) NOT NULL COMMENT '幸运礼物奖池 ID',
  gift_count BIGINT NOT NULL COMMENT '礼物数量',
  unit_amount BIGINT NOT NULL COMMENT '单个礼物金额，当前按 COIN 等价单位',
  total_amount BIGINT NOT NULL COMMENT '总金额，必须等于 gift_count * unit_amount',
  currency VARCHAR(16) NOT NULL DEFAULT 'COIN' COMMENT '金额币种',
  metadata_json JSON NOT NULL COMMENT '外部 App 扩展元数据',
  rule_version BIGINT NOT NULL DEFAULT 0 COMMENT '命中规则版本；0 表示未启用规则',
  selected_tier_id VARCHAR(96) NOT NULL DEFAULT '' COMMENT '命中奖档',
  multiplier_ppm BIGINT NOT NULL DEFAULT 0 COMMENT '倍率，1x = 1000000',
  reward_amount BIGINT NOT NULL DEFAULT 0 COMMENT '返回给外部 App 处理的奖励金额',
  reward_status VARCHAR(32) NOT NULL DEFAULT 'granted' COMMENT 'granted/failed；不代表 HyApp wallet 入账',
  paid_at_ms BIGINT NOT NULL COMMENT '外部 App 扣费完成时间，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, request_id),
  UNIQUE KEY uk_external_lucky_draw_id (app_code, draw_id),
  KEY idx_external_lucky_user (app_code, external_user_id, created_at_ms),
  KEY idx_external_lucky_pool (app_code, pool_id, created_at_ms),
  KEY idx_external_lucky_status (app_code, reward_status, created_at_ms),
  KEY idx_external_lucky_profile_cursor (app_code, created_at_ms, draw_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='外部 App 幸运礼物抽奖事实表';

CREATE TABLE IF NOT EXISTS external_lucky_gift_draw_items (
  app_code VARCHAR(32) NOT NULL COMMENT '外部 App 应用编码',
  request_id VARCHAR(128) NOT NULL COMMENT '聚合请求幂等 ID',
  item_index INT NOT NULL COMMENT '从1开始的顺序子抽序号',
  draw_id VARCHAR(128) NOT NULL COMMENT '子抽事实 ID',
  command_id VARCHAR(128) NOT NULL COMMENT '稳定子命令 ID',
  external_user_id VARCHAR(128) NOT NULL COMMENT '外部 App 用户 ID',
  pool_id VARCHAR(96) NOT NULL COMMENT '幸运礼物奖池 ID',
  rule_version BIGINT NOT NULL COMMENT '不可变规则版本',
  unit_amount BIGINT NOT NULL COMMENT '本抽实际金额',
  reward_amount BIGINT NOT NULL COMMENT '本抽奖励金额',
  selected_tier_id VARCHAR(96) NOT NULL COMMENT '本抽最终奖档',
  multiplier_ppm BIGINT NOT NULL COMMENT '本抽倍率',
  stage VARCHAR(32) NOT NULL COMMENT '充值分层；缺可信外部充值事实时为novice',
  candidate_snapshot_json JSON NOT NULL COMMENT '动态权重、删除重抽及大奖条件快照',
  pool_snapshot_json JSON NOT NULL COMMENT '本抽资金拆分和池快照',
  rtp_snapshot_json JSON NOT NULL COMMENT '本抽RTP快照',
  reward_status VARCHAR(32) NOT NULL DEFAULT 'granted' COMMENT '外部调用方自行结算',
  paid_at_ms BIGINT NOT NULL COMMENT '外部扣费时间，UTC epoch ms',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  PRIMARY KEY (app_code, request_id, item_index),
  UNIQUE KEY uk_external_lucky_item_draw (app_code, draw_id),
  KEY idx_external_lucky_item_user (app_code, external_user_id, created_at_ms),
  KEY idx_external_lucky_item_profile_cursor (app_code, created_at_ms, draw_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='外部dynamic_v3顺序子抽审计';

-- AB 实验事实表：两组各钉住一个不可变 rule_version，运行时按 bucket_salt + user 哈希分流。
-- active 生成列只在未完成状态为 1，配合唯一键保证同一奖池同时最多一个未完成实验。
CREATE TABLE IF NOT EXISTS lucky_gift_experiments (
  app_code VARCHAR(32) NOT NULL COMMENT '应用编码',
  experiment_id VARCHAR(64) NOT NULL COMMENT '实验 ID',
  pool_id VARCHAR(96) NOT NULL COMMENT '幸运礼物奖池 ID',
  name VARCHAR(128) NOT NULL COMMENT '实验名称',
  control_rule_version BIGINT NOT NULL COMMENT '对照组钉住的规则版本',
  treatment_rule_version BIGINT NOT NULL COMMENT '实验组钉住的规则版本',
  treatment_traffic_ppm BIGINT NOT NULL DEFAULT 0 COMMENT '实验组流量比例 ppm，0..1000000',
  bucket_salt VARCHAR(64) NOT NULL COMMENT '分桶盐；实验生命周期内不可变，保证同一用户分组稳定',
  status VARCHAR(16) NOT NULL DEFAULT 'running' COMMENT 'running/paused/completed',
  active TINYINT AS (IF(status IN ('running', 'paused'), 1, NULL)) STORED COMMENT '未完成实验为 1，completed 为 NULL',
  winner_arm VARCHAR(16) NOT NULL DEFAULT '' COMMENT '结束实验时选择的获胜组 control/treatment',
  winner_rule_version BIGINT NOT NULL DEFAULT 0 COMMENT '获胜组钉住的规则版本',
  final_rule_version BIGINT NOT NULL DEFAULT 0 COMMENT '结束时重发布的收敛版本，全量流量由它承接',
  created_by_admin_id BIGINT NOT NULL DEFAULT 0 COMMENT '创建管理员 ID',
  started_at_ms BIGINT NOT NULL COMMENT '实验开始时间，UTC epoch ms',
  ended_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, experiment_id),
  UNIQUE KEY uk_lucky_gift_experiments_active_pool (app_code, pool_id, active),
  KEY idx_lucky_gift_experiments_pool (app_code, pool_id, started_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物 AB 实验';

-- 白名单 override：把指定用户强制固定到某个组，用于放量前验证。
CREATE TABLE IF NOT EXISTS lucky_gift_experiment_overrides (
  app_code VARCHAR(32) NOT NULL COMMENT '应用编码',
  experiment_id VARCHAR(64) NOT NULL COMMENT '实验 ID',
  -- user_key 必须字节精确（binary collation）：FNV 分桶按字节计算，ci 排序规则会让大小写不同的外部用户碰撞/失配。
  user_key VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '用户标识：内部十进制 user_id 或 ext:external_user_id',
  arm VARCHAR(16) NOT NULL COMMENT '强制组 control/treatment',
  created_by_admin_id BIGINT NOT NULL DEFAULT 0 COMMENT '操作管理员 ID',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  PRIMARY KEY (app_code, experiment_id, user_key)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物 AB 实验用户白名单';
