SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci;


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

USE hyapp_wallet;

CREATE TABLE IF NOT EXISTS wallet_accounts (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  user_id BIGINT NOT NULL COMMENT '用户 ID',
  asset_type VARCHAR(32) NOT NULL COMMENT '钱包资产类型',
  available_amount BIGINT NOT NULL COMMENT '可用数量',
  frozen_amount BIGINT NOT NULL COMMENT '冻结数量',
  version BIGINT NOT NULL 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, user_id, asset_type)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='钱包账户余额表';

CREATE TABLE IF NOT EXISTS wallet_transactions (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  transaction_id VARCHAR(96) NOT NULL COMMENT '钱包交易 ID',
  command_id VARCHAR(128) NOT NULL COMMENT '业务命令幂等 ID',
  biz_type VARCHAR(64) NOT NULL COMMENT '业务类型',
  status VARCHAR(32) NOT NULL COMMENT '业务状态',
  request_hash VARCHAR(128) NOT NULL COMMENT '请求哈希值',
  external_ref VARCHAR(128) NOT NULL DEFAULT '' COMMENT '外部引用',
  metadata_json JSON NULL COMMENT '扩展元数据 JSON',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  updated_at_ms BIGINT NOT NULL COMMENT '更新时间，UTC epoch ms',
  PRIMARY KEY (app_code, transaction_id),
  UNIQUE KEY uk_wallet_tx_command (app_code, command_id),
  KEY idx_wallet_tx_biz_time (app_code, biz_type, created_at_ms),
  KEY idx_wallet_tx_external_ref (app_code, external_ref)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='钱包交易主表';

CREATE TABLE IF NOT EXISTS wallet_entries (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  entry_id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '流水 ID',
  transaction_id VARCHAR(96) NOT NULL COMMENT '钱包交易 ID',
  user_id BIGINT NOT NULL COMMENT '用户 ID',
  asset_type VARCHAR(32) NOT NULL COMMENT '钱包资产类型',
  available_delta BIGINT NOT NULL COMMENT '可用变动',
  frozen_delta BIGINT NOT NULL COMMENT '冻结变动',
  available_after BIGINT NOT NULL COMMENT '可用后',
  frozen_after BIGINT NOT NULL COMMENT '冻结后',
  counterparty_user_id BIGINT NOT NULL DEFAULT 0 COMMENT '交易对手用户 ID',
  room_id VARCHAR(96) NOT NULL DEFAULT '' COMMENT '房间 ID',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  KEY idx_wallet_entries_user_time (app_code, user_id, created_at_ms),
  KEY idx_wallet_entries_tx (app_code, transaction_id),
  KEY idx_wallet_entries_asset_time (app_code, asset_type, created_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='钱包复式流水表';

CREATE TABLE IF NOT EXISTS wallet_outbox (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  event_id VARCHAR(128) NOT NULL COMMENT '事件幂等 ID',
  event_type VARCHAR(64) NOT NULL COMMENT '事件类型',
  transaction_id VARCHAR(96) NOT NULL COMMENT '钱包交易 ID',
  command_id VARCHAR(128) NOT NULL COMMENT '业务命令幂等 ID',
  user_id BIGINT NOT NULL COMMENT '用户 ID',
  asset_type VARCHAR(32) NOT NULL COMMENT '钱包资产类型',
  available_delta BIGINT NOT NULL COMMENT '可用变动',
  frozen_delta BIGINT NOT NULL COMMENT '冻结变动',
  payload JSON NOT NULL COMMENT '业务负载快照',
  status VARCHAR(32) NOT NULL COMMENT '业务状态',
  worker_id VARCHAR(128) NOT NULL DEFAULT '' COMMENT 'MQ 投递 worker ID',
  lock_until_ms BIGINT NULL COMMENT 'MQ 投递锁过期时间，UTC epoch ms',
  retry_count INT NOT NULL DEFAULT 0 COMMENT '重试次数',
  next_retry_at_ms BIGINT NULL COMMENT '下一次 MQ 投递重试时间，UTC epoch ms',
  last_error TEXT NULL 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, event_id),
  KEY idx_wallet_outbox_pending (app_code, status, next_retry_at_ms, created_at_ms, event_id),
  KEY idx_wallet_outbox_claim (app_code, status, lock_until_ms, created_at_ms, event_id),
  KEY idx_wallet_outbox_event_pending (app_code, status, event_type, next_retry_at_ms, created_at_ms, event_id),
  KEY idx_wallet_outbox_event_claim (app_code, status, event_type, lock_until_ms, created_at_ms, event_id),
  KEY idx_wallet_outbox_retention (app_code, status, updated_at_ms, event_id),
  KEY idx_wallet_outbox_event_created (app_code, event_type, created_at_ms, event_id),
  KEY idx_wallet_outbox_asset_event_created (app_code, asset_type, event_type, created_at_ms, event_id),
  KEY idx_wallet_outbox_tx (app_code, transaction_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='钱包事件 outbox 表';

-- 主播工资周期钻石账户：只记录政策结算用累计值，不作为用户可消费或可提现的钱包资产。
-- cycle_key 当前固定为 UTC yyyy-MM；后续日结/半月结不清空该账户，月末清算任务按策略处理。
CREATE TABLE IF NOT EXISTS host_period_diamond_accounts (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  user_id BIGINT NOT NULL COMMENT '主播用户 ID',
  cycle_key VARCHAR(16) NOT NULL COMMENT '工资周期键，UTC yyyy-MM',
  region_id BIGINT NOT NULL COMMENT '主播身份所属区域 ID，用于匹配区域工资政策',
  agency_owner_user_id BIGINT NOT NULL DEFAULT 0 COMMENT '送礼入账时主播归属 Agency 的 owner 用户 ID，0 表示无代理收款人',
  total_diamonds BIGINT NOT NULL DEFAULT 0 COMMENT '周期累计钻石',
  gift_diamond_total BIGINT NOT NULL DEFAULT 0 COMMENT '送礼产生的周期钻石累计',
  version BIGINT NOT NULL DEFAULT 1 COMMENT '版本号',
  first_gift_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '本周期首次收礼时间，UTC epoch ms',
  last_gift_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, user_id, cycle_key),
  KEY idx_host_period_diamond_region_cycle (app_code, region_id, cycle_key),
  KEY idx_host_period_diamond_cycle_total (app_code, cycle_key, total_diamonds)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='主播工资周期钻石账户表';

-- 主播工资周期钻石流水：每笔成功送礼只在 target 为 active host 时写入，用于审计和补偿重建周期账户。
CREATE TABLE IF NOT EXISTS host_period_diamond_entries (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  entry_id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '流水 ID',
  transaction_id VARCHAR(96) NOT NULL COMMENT '钱包交易 ID',
  command_id VARCHAR(128) NOT NULL COMMENT '业务命令幂等 ID',
  user_id BIGINT NOT NULL COMMENT '主播用户 ID',
  cycle_key VARCHAR(16) NOT NULL COMMENT '工资周期键，UTC yyyy-MM',
  region_id BIGINT NOT NULL COMMENT '主播身份所属区域 ID',
  agency_owner_user_id BIGINT NOT NULL DEFAULT 0 COMMENT '本次送礼入账使用的代理收款用户快照',
  diamond_delta BIGINT NOT NULL COMMENT '本次增加钻石',
  diamond_after BIGINT NOT NULL COMMENT '本次入账后周期累计钻石',
  gift_charge_asset_type VARCHAR(32) NOT NULL DEFAULT 'COIN' COMMENT '礼物扣费资产类型快照',
  gift_charge_amount BIGINT NOT NULL DEFAULT 0 COMMENT '礼物扣费金额快照',
  gift_id VARCHAR(96) NOT NULL DEFAULT '' COMMENT '礼物 ID',
  gift_count INT NOT NULL DEFAULT 0 COMMENT '礼物数量',
  sender_user_id BIGINT NOT NULL DEFAULT 0 COMMENT '送礼用户 ID',
  room_id VARCHAR(96) NOT NULL DEFAULT '' COMMENT '房间 ID',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  UNIQUE KEY uk_host_period_diamond_tx (app_code, transaction_id, user_id, cycle_key),
  KEY idx_host_period_diamond_entries_user_cycle (app_code, user_id, cycle_key, created_at_ms),
  KEY idx_host_period_diamond_entries_region_cycle (app_code, region_id, cycle_key, created_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='主播工资周期钻石流水表';

-- 运行侧工资政策表：字段与 admin_host_agency_salary_policies 对齐，wallet-service 结算只读取这里的已发布快照。
-- 后台配置仍由 admin-server 管理；同步/导入时必须整份写入 policy + levels，结算事务不直接读 admin 库。
CREATE TABLE IF NOT EXISTS host_agency_salary_policies (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  policy_id BIGINT UNSIGNED NOT NULL COMMENT '工资政策 ID，来自后台配置',
  name VARCHAR(120) NOT NULL DEFAULT '' COMMENT '政策名称',
  region_id BIGINT NOT NULL COMMENT '适用区域 ID',
  status VARCHAR(24) NOT NULL DEFAULT 'disabled' COMMENT '状态：active/disabled',
  settlement_mode VARCHAR(24) NOT NULL DEFAULT 'daily' COMMENT '结算方式：daily/half_month',
  settlement_trigger_mode VARCHAR(24) NOT NULL DEFAULT 'automatic' COMMENT '结算触发方式：automatic/manual',
  gift_coin_to_diamond_ratio DECIMAL(18,6) NOT NULL DEFAULT 1.000000 COMMENT '礼物金币转主播钻石比例快照',
  residual_diamond_to_usd_rate DECIMAL(24,12) NOT NULL DEFAULT 0.000000000000 COMMENT '月底剩余钻石转美元比例',
  effective_from_ms BIGINT NOT NULL DEFAULT 0 COMMENT '生效开始时间，UTC epoch ms',
  effective_to_ms 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, policy_id),
  KEY idx_host_agency_salary_policy_active (app_code, region_id, status, settlement_mode, settlement_trigger_mode, effective_from_ms, effective_to_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='主播代理工资政策运行快照表';

CREATE TABLE IF NOT EXISTS host_agency_salary_policy_levels (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  policy_id BIGINT UNSIGNED NOT NULL COMMENT '工资政策 ID',
  level_no INT NOT NULL COMMENT '等级',
  required_diamonds BIGINT NOT NULL COMMENT '达到该等级所需主播当月钻石',
  host_salary_usd_minor BIGINT NOT NULL DEFAULT 0 COMMENT '主播累计美元工资，单位美分',
  host_coin_reward BIGINT NOT NULL DEFAULT 0 COMMENT '主播累计金币奖励',
  agency_salary_usd_minor BIGINT NOT NULL DEFAULT 0 COMMENT '代理累计美元工资，单位美分',
  status VARCHAR(24) NOT NULL DEFAULT 'active' COMMENT '等级状态：active/disabled',
  sort_order INT 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, policy_id, level_no),
  KEY idx_host_agency_salary_policy_level_required (app_code, policy_id, status, required_diamonds)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='主播代理工资政策等级运行快照表';

-- 结算进度按主播+月份独立记录累计已发值；日结/半月结只更新累计，月底清算只打 cleared 标记。
-- 这里不覆盖 host_period_diamond_accounts.total_diamonds，历史累计钻石必须可审计和可重放。
CREATE TABLE IF NOT EXISTS host_salary_settlement_progress (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  user_id BIGINT NOT NULL COMMENT '主播用户 ID',
  cycle_key VARCHAR(16) NOT NULL COMMENT '工资周期键，UTC yyyy-MM',
  settled_level_no INT NOT NULL DEFAULT 0 COMMENT '已结算到的最高等级',
  settled_host_salary_usd_minor BIGINT NOT NULL DEFAULT 0 COMMENT '已发主播美元工资累计，单位美分',
  settled_host_coin_reward BIGINT NOT NULL DEFAULT 0 COMMENT '已发主播金币奖励累计',
  settled_agency_salary_usd_minor BIGINT NOT NULL DEFAULT 0 COMMENT '已发代理美元工资累计，单位美分',
  last_settled_total_diamonds BIGINT NOT NULL DEFAULT 0 COMMENT '上次结算任务已处理到的周期累计钻石，避免未升档时重复空跑',
  residual_usd_minor BIGINT NOT NULL DEFAULT 0 COMMENT '月底剩余钻石已转主播美元金额，单位美分',
  month_end_cleared_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '月底清算完成时间，0 表示未清算',
  last_policy_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '最后一次使用的政策 ID',
  version BIGINT NOT NULL DEFAULT 1 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, user_id, cycle_key),
  KEY idx_host_salary_settlement_progress_cycle (app_code, cycle_key, month_end_cleared_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='主播工资周期结算进度表';

CREATE TABLE IF NOT EXISTS host_salary_settlement_records (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  settlement_id VARCHAR(128) NOT NULL COMMENT '结算记录 ID',
  command_id VARCHAR(128) NOT NULL COMMENT '钱包交易幂等命令 ID',
  transaction_id VARCHAR(96) NOT NULL COMMENT '钱包交易 ID',
  settlement_type VARCHAR(24) NOT NULL COMMENT '结算类型：daily/half_month/month_end',
  user_id BIGINT NOT NULL COMMENT '主播用户 ID',
  agency_owner_user_id BIGINT NOT NULL DEFAULT 0 COMMENT '代理收款用户 ID',
  cycle_key VARCHAR(16) NOT NULL COMMENT '工资周期键，UTC yyyy-MM',
  policy_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '使用的政策 ID',
  level_no INT NOT NULL DEFAULT 0 COMMENT '本次结算后的等级',
  total_diamonds BIGINT NOT NULL DEFAULT 0 COMMENT '结算时周期累计钻石',
  host_salary_usd_minor_delta BIGINT NOT NULL DEFAULT 0 COMMENT '本次主播美元工资增量，单位美分',
  host_coin_reward_delta BIGINT NOT NULL DEFAULT 0 COMMENT '本次主播金币奖励增量',
  agency_salary_usd_minor_delta BIGINT NOT NULL DEFAULT 0 COMMENT '本次代理美元工资增量，单位美分',
  residual_usd_minor_delta BIGINT NOT NULL DEFAULT 0 COMMENT '本次月底剩余钻石转美元增量，单位美分',
  status VARCHAR(24) NOT NULL DEFAULT 'succeeded' COMMENT '状态：succeeded/skipped/failed',
  reason VARCHAR(255) NOT NULL DEFAULT '' COMMENT '跳过或失败原因',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  PRIMARY KEY (app_code, settlement_id),
  UNIQUE KEY uk_host_salary_settlement_command (app_code, command_id),
  KEY idx_host_salary_settlement_user_cycle (app_code, user_id, cycle_key, created_at_ms),
  KEY idx_host_salary_settlement_agency_cycle (app_code, agency_owner_user_id, cycle_key, created_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='主播代理工资结算记录表';

CREATE TABLE IF NOT EXISTS team_salary_settlement_progress (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  policy_type VARCHAR(24) NOT NULL COMMENT '团队工资类型：bd/admin',
  user_id BIGINT NOT NULL COMMENT '收款用户 ID：BD 或 Admin',
  cycle_key VARCHAR(16) NOT NULL COMMENT '工资周期键，UTC yyyy-MM',
  region_id BIGINT NOT NULL COMMENT '结算时使用的区域 ID',
  settled_level_no INT NOT NULL DEFAULT 0 COMMENT '已结算到的最高等级',
  settled_salary_usd_minor BIGINT NOT NULL DEFAULT 0 COMMENT '已发团队工资累计，单位美分',
  last_settled_income_usd_minor BIGINT NOT NULL DEFAULT 0 COMMENT '上次已处理收入累计，单位美分，用于避免未升档重复空跑',
  last_policy_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '最后一次使用的政策 ID',
  month_closed_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '完整月结算关闭时间，0 表示未关闭',
  version BIGINT NOT NULL DEFAULT 1 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, policy_type, user_id, cycle_key),
  KEY idx_team_salary_progress_cycle (app_code, policy_type, cycle_key, region_id, month_closed_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='BD/Admin 工资周期结算进度表';

CREATE TABLE IF NOT EXISTS team_salary_settlement_records (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  settlement_id VARCHAR(128) NOT NULL COMMENT '结算记录 ID',
  command_id VARCHAR(128) NOT NULL COMMENT '钱包交易幂等命令 ID',
  transaction_id VARCHAR(96) NOT NULL COMMENT '钱包交易 ID',
  policy_type VARCHAR(24) NOT NULL COMMENT '团队工资类型：bd/admin',
  trigger_mode VARCHAR(24) NOT NULL DEFAULT 'manual' COMMENT '触发方式：automatic/manual',
  user_id BIGINT NOT NULL COMMENT '收款用户 ID：BD 或 Admin',
  cycle_key VARCHAR(16) NOT NULL COMMENT '工资周期键，UTC yyyy-MM',
  region_id BIGINT NOT NULL COMMENT '结算时使用的区域 ID',
  policy_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '使用的政策 ID',
  level_no INT NOT NULL DEFAULT 0 COMMENT '本次结算后的等级',
  income_usd_minor BIGINT NOT NULL DEFAULT 0 COMMENT '结算时团队收入累计，单位美分',
  salary_usd_minor_delta BIGINT NOT NULL DEFAULT 0 COMMENT '本次团队美元工资增量，单位美分',
  status VARCHAR(24) NOT NULL DEFAULT 'succeeded' COMMENT '状态：succeeded/skipped/failed',
  reason VARCHAR(255) NOT NULL DEFAULT '' COMMENT '跳过或失败原因',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  PRIMARY KEY (app_code, settlement_id),
  UNIQUE KEY uk_team_salary_settlement_command (app_code, command_id),
  KEY idx_team_salary_records_user_cycle (app_code, policy_type, user_id, cycle_key, created_at_ms),
  KEY idx_team_salary_records_cycle (app_code, policy_type, cycle_key, region_id, created_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='BD/Admin 工资结算记录表';

-- 老环境已建过主播周期账户时，CREATE TABLE IF NOT EXISTS 不会补新字段；结算前必须有代理收款快照。
SET @ddl := IF(
  (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'host_period_diamond_accounts' AND COLUMN_NAME = 'agency_owner_user_id') = 0,
  'ALTER TABLE host_period_diamond_accounts ADD COLUMN agency_owner_user_id BIGINT NOT NULL DEFAULT 0 COMMENT ''送礼入账时主播归属 Agency 的 owner 用户 ID，0 表示无代理收款人'' AFTER region_id',
  '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 = 'host_period_diamond_entries' AND COLUMN_NAME = 'agency_owner_user_id') = 0,
  'ALTER TABLE host_period_diamond_entries ADD COLUMN agency_owner_user_id BIGINT NOT NULL DEFAULT 0 COMMENT ''本次送礼入账使用的代理收款用户快照'' AFTER region_id',
  '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 = 'host_agency_salary_policies' AND COLUMN_NAME = 'settlement_trigger_mode') = 0,
  'ALTER TABLE host_agency_salary_policies ADD COLUMN settlement_trigger_mode VARCHAR(24) NOT NULL DEFAULT ''automatic'' COMMENT ''结算触发方式：automatic/manual'' AFTER settlement_mode',
  '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 = 'host_salary_settlement_progress' AND COLUMN_NAME = 'last_settled_total_diamonds') = 0,
  'ALTER TABLE host_salary_settlement_progress ADD COLUMN last_settled_total_diamonds BIGINT NOT NULL DEFAULT 0 COMMENT ''上次结算任务已处理到的周期累计钻石，避免未升档时重复空跑'' AFTER settled_agency_salary_usd_minor',
  'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

-- 老环境可能已经存在 wallet_outbox，CREATE TABLE IF NOT EXISTS 不会补齐后续新增的投递锁字段。
-- 这里用 information_schema 生成幂等 ALTER，保证重复执行 initdb 时不会因重复列名失败。
SET @ddl := IF(
  (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'wallet_outbox' AND COLUMN_NAME = 'worker_id') = 0,
  'ALTER TABLE wallet_outbox ADD COLUMN worker_id VARCHAR(128) NOT NULL DEFAULT '''' COMMENT ''MQ 投递 worker ID'' AFTER status',
  'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

-- 投递锁过期时间用于多实例 claim outbox，老库缺这个列时会导致 worker 查询直接 1054。
SET @ddl := IF(
  (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'wallet_outbox' AND COLUMN_NAME = 'lock_until_ms') = 0,
  'ALTER TABLE wallet_outbox ADD COLUMN lock_until_ms BIGINT NULL COMMENT ''MQ 投递锁过期时间，UTC epoch ms'' AFTER worker_id',
  'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

-- 下一次重试时间让失败 outbox 可延迟重投；老库缺列时待投递扫描会直接失败。
SET @ddl := IF(
  (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'wallet_outbox' AND COLUMN_NAME = 'next_retry_at_ms') = 0,
  'ALTER TABLE wallet_outbox ADD COLUMN next_retry_at_ms BIGINT NULL COMMENT ''下一次 MQ 投递重试时间，UTC epoch ms'' AFTER retry_count',
  'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

-- pending 索引的列顺序跟 outbox 扫描条件绑定；为兼容历史索引，存在就先删除再按当前结构重建。
SET @ddl := IF(
  (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'wallet_outbox' AND INDEX_NAME = 'idx_wallet_outbox_pending') > 0,
  'ALTER TABLE wallet_outbox DROP INDEX idx_wallet_outbox_pending',
  'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

SET @ddl := 'ALTER TABLE wallet_outbox ADD INDEX idx_wallet_outbox_pending (app_code, status, next_retry_at_ms, created_at_ms, event_id)';
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

-- claim 索引用于查找锁过期的消息；列顺序也跟查询条件绑定，存在旧结构时重建。
SET @ddl := IF(
  (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'wallet_outbox' AND INDEX_NAME = 'idx_wallet_outbox_claim') > 0,
  'ALTER TABLE wallet_outbox DROP INDEX idx_wallet_outbox_claim',
  'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

SET @ddl := 'ALTER TABLE wallet_outbox ADD INDEX idx_wallet_outbox_claim (app_code, status, lock_until_ms, created_at_ms, event_id)';
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

-- 实时红包/房间 UI 事件按 event_type 独立 claim；缺这个索引会在通用账务 backlog 上扫描，仍然可能延迟弹窗。
SET @ddl := IF(
  (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'wallet_outbox' AND INDEX_NAME = 'idx_wallet_outbox_event_pending') = 0,
  'ALTER TABLE wallet_outbox ADD INDEX idx_wallet_outbox_event_pending (app_code, status, event_type, next_retry_at_ms, created_at_ms, event_id)',
  '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 = 'wallet_outbox' AND INDEX_NAME = 'idx_wallet_outbox_event_claim') = 0,
  'ALTER TABLE wallet_outbox ADD INDEX idx_wallet_outbox_event_claim (app_code, status, event_type, lock_until_ms, created_at_ms, event_id)',
  '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 = 'wallet_outbox' AND INDEX_NAME = 'idx_wallet_outbox_retention') = 0,
  'ALTER TABLE wallet_outbox ADD INDEX idx_wallet_outbox_retention (app_code, status, updated_at_ms, event_id)',
  'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

-- projection worker 只扫描单租户、单事件类型的 wallet_outbox；缺少该索引会退化成百万级全表扫描。
SET @ddl := IF(
  (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'wallet_outbox' AND INDEX_NAME = 'idx_wallet_outbox_event_created') = 0,
  'ALTER TABLE wallet_outbox ADD INDEX idx_wallet_outbox_event_created (app_code, event_type, created_at_ms, event_id)',
  '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 = 'wallet_outbox' AND INDEX_NAME = 'idx_wallet_outbox_asset_event_created') = 0,
  'ALTER TABLE wallet_outbox ADD INDEX idx_wallet_outbox_asset_event_created (app_code, asset_type, event_type, created_at_ms, event_id)',
  'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

CREATE TABLE IF NOT EXISTS wallet_gift_prices (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  gift_id VARCHAR(96) NOT NULL COMMENT '礼物 ID',
  price_version VARCHAR(64) NOT NULL COMMENT '价格版本',
  status VARCHAR(32) NOT NULL COMMENT '业务状态',
  charge_asset_type VARCHAR(32) NOT NULL DEFAULT 'COIN' COMMENT '扣费资产类型',
  coin_price BIGINT NOT NULL COMMENT '金币价格',
  gift_point_amount BIGINT NOT NULL COMMENT '历史字段：GIFT_POINT 已下线，新写入固定 0',
  heat_value BIGINT NOT NULL COMMENT '热度值',
  effective_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, gift_id, price_version),
  KEY idx_wallet_gift_prices_effective (app_code, gift_id, status, effective_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='钱包礼物价格表';

CREATE TABLE IF NOT EXISTS wallet_recharge_policies (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  policy_id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '策略 ID',
  region_id BIGINT NOT NULL COMMENT '区域 ID',
  policy_version VARCHAR(64) NOT NULL COMMENT '策略版本',
  status VARCHAR(32) NOT NULL COMMENT '业务状态',
  currency_code VARCHAR(3) NOT NULL DEFAULT 'USD' COMMENT '币种编码',
  coin_amount BIGINT NOT NULL COMMENT '金币数量',
  usd_minor_amount BIGINT NOT NULL COMMENT '美元最小单位数量',
  effective_from_ms BIGINT NOT NULL COMMENT '生效开始时间，UTC epoch ms',
  effective_to_ms BIGINT NULL COMMENT '生效结束时间，UTC epoch ms',
  created_by_user_id BIGINT NULL COMMENT '创建人用户 ID',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  updated_at_ms BIGINT NOT NULL COMMENT '更新时间，UTC epoch ms',
  KEY idx_wallet_recharge_policies_active (app_code, region_id, status, effective_from_ms),
  UNIQUE KEY uk_wallet_recharge_policy_version (app_code, region_id, policy_version)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='钱包充值策略表';

CREATE TABLE IF NOT EXISTS wallet_recharge_records (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  transaction_id VARCHAR(96) NOT NULL COMMENT '钱包交易 ID',
  user_id BIGINT NOT NULL COMMENT '用户 ID',
  recharge_sequence BIGINT NOT NULL DEFAULT 0 COMMENT '该用户成功充值序号，从 1 开始',
  seller_user_id BIGINT NOT NULL COMMENT '商户用户 ID',
  seller_region_id BIGINT NOT NULL COMMENT '商户区域 ID',
  target_region_id BIGINT NOT NULL COMMENT '目标区域 ID',
  policy_id BIGINT NOT NULL COMMENT '策略 ID',
  policy_version VARCHAR(64) NOT NULL COMMENT '策略版本',
  currency_code VARCHAR(8) NOT NULL COMMENT '币种编码',
  coin_amount BIGINT NOT NULL COMMENT '金币数量',
  usd_minor_amount BIGINT NOT NULL COMMENT '美元最小单位数量',
  exchange_coin_amount BIGINT NOT NULL COMMENT '兑换金币数量',
  exchange_usd_minor_amount BIGINT NOT NULL COMMENT '兑换美元最小单位数量',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  PRIMARY KEY (app_code, transaction_id),
  KEY idx_wallet_recharge_records_user_time (app_code, user_id, created_at_ms),
  KEY idx_wallet_recharge_records_seller_time (app_code, seller_user_id, created_at_ms),
  KEY idx_wallet_recharge_records_region_time (app_code, target_region_id, created_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='钱包充值记录表';

CREATE TABLE IF NOT EXISTS wallet_user_recharge_stats (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  user_id BIGINT NOT NULL COMMENT '用户 ID',
  recharge_count BIGINT NOT NULL DEFAULT 0 COMMENT '成功充值次数',
  first_transaction_id VARCHAR(96) NOT NULL DEFAULT '' COMMENT '首笔充值交易 ID',
  first_recharged_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '首笔充值时间，UTC epoch ms',
  total_coin_amount BIGINT NOT NULL DEFAULT 0 COMMENT '累计充值金币',
  total_usd_minor_amount 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, user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户充值统计表';

SET @ddl := IF(
  (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'wallet_recharge_records' AND COLUMN_NAME = 'recharge_sequence') = 0,
  'ALTER TABLE wallet_recharge_records ADD COLUMN recharge_sequence BIGINT NOT NULL DEFAULT 0 COMMENT ''该用户成功充值序号，从 1 开始'' AFTER user_id',
  'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

CREATE TABLE IF NOT EXISTS wallet_recharge_products (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  product_id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '商品 ID',
  product_code VARCHAR(128) NULL COMMENT '商品编码',
  product_name VARCHAR(128) NOT NULL COMMENT '商品名称',
  description VARCHAR(512) NOT NULL DEFAULT '' COMMENT '描述信息',
  audience_type VARCHAR(32) NOT NULL DEFAULT 'normal' COMMENT '购买对象：normal 普通用户，coin_seller 币商',
  platform VARCHAR(16) NOT NULL COMMENT '平台',
  channel VARCHAR(32) NOT NULL COMMENT '渠道',
  currency_code VARCHAR(8) NOT NULL DEFAULT 'USDT' COMMENT '币种编码',
  amount_micro BIGINT NOT NULL COMMENT '微单位金额',
  coin_amount BIGINT NOT NULL COMMENT '金币数量',
  resource_asset_type VARCHAR(32) NOT NULL DEFAULT 'COIN' COMMENT '资源资产类型',
  status VARCHAR(32) NOT NULL COMMENT '业务状态',
  sort_order INT NOT NULL DEFAULT 0 COMMENT '排序权重，数值越小越靠前',
  created_by_user_id BIGINT NULL COMMENT '创建人用户 ID',
  updated_by_user_id BIGINT NULL COMMENT '更新人用户 ID',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  updated_at_ms BIGINT NOT NULL COMMENT '更新时间，UTC epoch ms',
  UNIQUE KEY uk_wallet_recharge_products_code (app_code, product_code),
  KEY idx_wallet_recharge_products_scope (app_code, platform, audience_type, status, amount_micro, product_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='钱包充值商品表';

SET @ddl := IF(
  (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'wallet_recharge_products' AND COLUMN_NAME = 'audience_type') = 0,
  'ALTER TABLE wallet_recharge_products ADD COLUMN audience_type VARCHAR(32) NOT NULL DEFAULT ''normal'' COMMENT ''购买对象：normal 普通用户，coin_seller 币商'' AFTER description',
  'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

CREATE TABLE IF NOT EXISTS wallet_recharge_product_regions (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  product_id BIGINT NOT NULL COMMENT '商品 ID',
  region_id BIGINT NOT NULL COMMENT '区域 ID',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  PRIMARY KEY (app_code, product_id, region_id),
  KEY idx_wallet_recharge_product_regions_region (app_code, region_id, product_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='钱包充值商品区域表';

CREATE TABLE IF NOT EXISTS third_party_payment_channels (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  provider_code VARCHAR(32) NOT NULL COMMENT '三方支付渠道编码',
  provider_name VARCHAR(64) NOT NULL COMMENT '三方支付渠道名称',
  status VARCHAR(32) NOT NULL DEFAULT 'active' COMMENT '渠道状态',
  sort_order INT 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, provider_code),
  KEY idx_third_party_payment_channels_status (app_code, status, sort_order)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='三方支付渠道表';

CREATE TABLE IF NOT EXISTS third_party_payment_methods (
  method_id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '支付方式 ID',
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  provider_code VARCHAR(32) NOT NULL COMMENT '三方支付渠道编码',
  country_code VARCHAR(8) NOT NULL COMMENT '国家码，GLOBAL 表示全球方式',
  country_name VARCHAR(64) NOT NULL DEFAULT '' COMMENT '国家名称',
  currency_code VARCHAR(8) NOT NULL COMMENT '下单币种',
  pay_way VARCHAR(64) NOT NULL COMMENT 'MiFaPay payWay',
  pay_type VARCHAR(64) NOT NULL COMMENT 'MiFaPay payType',
  method_name VARCHAR(128) NOT NULL COMMENT '支付方式名称',
  logo_url VARCHAR(1024) NOT NULL DEFAULT '' COMMENT '支付方式图标',
  status VARCHAR(32) NOT NULL DEFAULT 'active' COMMENT '方式状态',
  usd_to_currency_rate DECIMAL(20,8) NOT NULL DEFAULT 1 COMMENT 'USD 到支付币种汇率',
  sort_order INT 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',
  UNIQUE KEY uk_third_party_payment_methods_scope (app_code, provider_code, country_code, pay_way, pay_type),
  KEY idx_third_party_payment_methods_h5 (app_code, provider_code, country_code, status, sort_order),
  CONSTRAINT fk_third_party_payment_methods_channel FOREIGN KEY (app_code, provider_code) REFERENCES third_party_payment_channels(app_code, provider_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='三方支付国家方式配置表';

CREATE TABLE IF NOT EXISTS external_recharge_orders (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  order_id VARCHAR(96) NOT NULL COMMENT '外部充值订单号',
  command_id VARCHAR(128) NOT NULL COMMENT 'H5 幂等命令 ID',
  target_user_id BIGINT NOT NULL COMMENT '目标用户 ID',
  target_region_id BIGINT NOT NULL COMMENT '目标区域 ID',
  target_country_code VARCHAR(8) NOT NULL DEFAULT '' COMMENT '目标国家码',
  audience_type VARCHAR(32) NOT NULL COMMENT '购买对象',
  product_id BIGINT NOT NULL COMMENT '商品 ID',
  product_code VARCHAR(128) NOT NULL COMMENT '商品编码快照',
  product_name VARCHAR(128) NOT NULL COMMENT '商品名称快照',
  coin_amount BIGINT NOT NULL COMMENT '到账金币数量',
  usd_minor_amount BIGINT NOT NULL COMMENT 'USD cent 金额快照',
  provider_code VARCHAR(32) NOT NULL COMMENT '支付渠道',
  payment_method_id BIGINT NOT NULL DEFAULT 0 COMMENT '三方支付方式 ID',
  country_code VARCHAR(8) NOT NULL DEFAULT '' COMMENT '支付方式国家码',
  currency_code VARCHAR(8) NOT NULL DEFAULT '' COMMENT '支付币种',
  provider_amount_minor BIGINT NOT NULL DEFAULT 0 COMMENT '三方支付币种最小单位金额',
  pay_way VARCHAR(64) NOT NULL DEFAULT '' COMMENT 'MiFaPay payWay',
  pay_type VARCHAR(64) NOT NULL DEFAULT '' COMMENT 'MiFaPay payType',
  pay_url VARCHAR(2048) NOT NULL DEFAULT '' COMMENT '三方支付跳转 URL',
  provider_order_id VARCHAR(128) NOT NULL DEFAULT '' COMMENT '三方支付订单号',
  tx_hash VARCHAR(128) NOT NULL DEFAULT '' COMMENT 'USDT tx hash',
  receive_address VARCHAR(128) NOT NULL DEFAULT '' COMMENT 'USDT 收款地址',
  status VARCHAR(32) NOT NULL COMMENT '订单状态',
  failure_reason VARCHAR(512) NOT NULL DEFAULT '' COMMENT '失败原因',
  wallet_transaction_id VARCHAR(96) NOT NULL DEFAULT '' COMMENT '钱包交易 ID',
  provider_payload JSON NULL 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, order_id),
  UNIQUE KEY uk_external_recharge_orders_command (app_code, command_id),
  KEY idx_external_recharge_orders_user_time (app_code, target_user_id, created_at_ms),
  KEY idx_external_recharge_orders_provider_order (app_code, provider_code, provider_order_id),
  KEY idx_external_recharge_orders_tx (app_code, provider_code, tx_hash)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='H5 外部充值订单表';

SET @now_ms = CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED);

INSERT IGNORE INTO third_party_payment_channels (app_code, provider_code, provider_name, status, sort_order, created_at_ms, updated_at_ms)
VALUES ('lalu', 'mifapay', 'MiFaPay', 'active', 10, @now_ms, @now_ms);

-- MiFaPay 是 H5 统一三方支付入口；真实商户号、商户标识、商户私钥、平台公钥只放运行环境配置。
-- 国家和支付方式默认打开，运营可在后台逐项关闭；默认汇率为 1，避免新环境缺配置时 H5 完全不可见。
INSERT IGNORE INTO third_party_payment_methods (
  app_code, provider_code, country_code, country_name, currency_code, pay_way, pay_type,
  method_name, logo_url, status, usd_to_currency_rate, sort_order, created_at_ms, updated_at_ms
) VALUES
  ('lalu', 'mifapay', 'ID', 'Indonesia', 'IDR', 'BankTransfer', 'BCA', 'BCA Bank', '', 'active', 1, 110, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'ID', 'Indonesia', 'IDR', 'BankTransfer', 'BNI', 'BNI Bank', '', 'active', 1, 120, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'ID', 'Indonesia', 'IDR', 'BankTransfer', 'BRI', 'BRI Bank', '', 'active', 1, 130, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'ID', 'Indonesia', 'IDR', 'BankTransfer', 'Mandiri', 'Mandiri Bank', '', 'active', 1, 140, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'ID', 'Indonesia', 'IDR', 'BankTransfer', 'Permata', 'Permata Bank', '', 'active', 1, 150, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'ID', 'Indonesia', 'IDR', 'Ewallet', 'DANA', 'DANA', '', 'active', 1, 160, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'ID', 'Indonesia', 'IDR', 'Ewallet', 'LinkAja', 'LinkAja', '', 'active', 1, 170, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'ID', 'Indonesia', 'IDR', 'Ewallet', 'OVO', 'OVO', '', 'active', 1, 180, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'ID', 'Indonesia', 'IDR', 'Ewallet', 'ShopeePay', 'ShopeePay', '', 'active', 1, 190, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'ID', 'Indonesia', 'IDR', 'QR', 'QRIS', 'QRIS', '', 'active', 1, 200, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'VN', 'Vietnam', 'VND', 'BankTransfer', 'VN_BankTransfer', 'Vietnam Bank Transfer', '', 'active', 1, 210, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'VN', 'Vietnam', 'VND', 'QR', 'VietQR', 'VietQR', '', 'active', 1, 220, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'BH', 'Bahrain', 'BHD', 'Card', 'CreditCard', 'Bahrain Credit Card', '', 'active', 1, 310, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'QA', 'Qatar', 'QAR', 'Card', 'CreditCard', 'Qatar Credit Card', '', 'active', 1, 410, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'OM', 'Oman', 'OMR', 'Card', 'CreditCard', 'Oman Credit Card', '', 'active', 1, 510, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'AE', 'United Arab Emirates', 'AED', 'Card', 'CreditCard', 'UAE Credit Card', '', 'active', 1, 610, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'KW', 'Kuwait', 'KWD', 'Card', 'Knet', 'KNET', '', 'active', 1, 710, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'SA', 'Saudi Arabia', 'SAR', 'Card', 'MADA', 'MADA', '', 'active', 1, 810, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'SA', 'Saudi Arabia', 'SAR', 'Ewallet', 'ApplePay', 'ApplePay', '', 'active', 1, 820, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'SA', 'Saudi Arabia', 'SAR', 'Ewallet', 'STCPay', 'STCPay', '', 'active', 1, 830, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'IN', 'India', 'INR', 'Ewallet', 'BHIM', 'BHIM', '', 'active', 1, 910, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'IN', 'India', 'INR', 'Ewallet', 'GooglePay', 'GooglePay', '', 'active', 1, 920, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'IN', 'India', 'INR', 'Ewallet', 'Mobikwik', 'Mobikwik', '', 'active', 1, 930, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'IN', 'India', 'INR', 'Ewallet', 'Paytm', 'Paytm', '', 'active', 1, 940, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'IN', 'India', 'INR', 'Ewallet', 'PhonePe', 'PhonePe', '', 'active', 1, 950, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'IN', 'India', 'INR', 'Ewallet', 'UPI', 'UPI', '', 'active', 1, 960, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'BD', 'Bangladesh', 'BDT', 'Ewallet', 'bKash', 'bKash', '', 'active', 1, 1010, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'PK', 'Pakistan', 'PKR', 'Ewallet', 'Easypaisa', 'Easypaisa', '', 'active', 1, 1110, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'PK', 'Pakistan', 'PKR', 'Ewallet', 'JazzCash', 'JazzCash', '', 'active', 1, 1120, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'EG', 'Egypt', 'EGP', 'Ewallet', 'FawryPay', 'FawryPay', '', 'active', 1, 1210, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'EG', 'Egypt', 'EGP', 'Ewallet', 'Meeza', 'Meeza', '', 'active', 1, 1220, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'EG', 'Egypt', 'EGP', 'Ewallet', 'Orange', 'Orange', '', 'active', 1, 1230, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'EG', 'Egypt', 'EGP', 'Ewallet', 'Vodafone', 'Vodafone', '', 'active', 1, 1240, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'PH', 'Philippines', 'PHP', 'Ewallet', 'Gcash', 'GCash', '', 'active', 1, 1310, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'PH', 'Philippines', 'PHP', 'Ewallet', 'PayMaya', 'PayMaya', '', 'active', 1, 1320, @now_ms, @now_ms),
  ('lalu', 'mifapay', 'PH', 'Philippines', 'PHP', 'QR', 'QRPH', 'QRPH', '', 'active', 1, 1330, @now_ms, @now_ms);

CREATE TABLE IF NOT EXISTS payment_orders (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  payment_order_id VARCHAR(96) NOT NULL COMMENT '平台支付订单 ID',
  provider VARCHAR(32) NOT NULL COMMENT '支付提供方',
  channel VARCHAR(32) NOT NULL COMMENT '充值渠道',
  status VARCHAR(32) NOT NULL COMMENT '订单状态',
  command_id VARCHAR(128) NOT NULL COMMENT '客户端确认命令幂等 ID',
  user_id BIGINT NOT NULL COMMENT '用户 ID',
  product_id BIGINT NOT NULL COMMENT '后台充值商品 ID',
  product_code VARCHAR(128) NOT NULL COMMENT 'Google Play 商品 ID',
  package_name VARCHAR(256) NOT NULL DEFAULT '' COMMENT 'Google Play 包名',
  provider_order_id VARCHAR(128) NOT NULL DEFAULT '' COMMENT 'Google Play orderId',
  purchase_token_hash VARCHAR(128) NOT NULL COMMENT 'Google purchase token SHA256，不落明文 token',
  purchase_state VARCHAR(32) NOT NULL DEFAULT '' COMMENT 'Google purchase state',
  consume_state VARCHAR(32) NOT NULL DEFAULT '' COMMENT 'Google consume 状态',
  wallet_transaction_id VARCHAR(96) NOT NULL DEFAULT '' COMMENT '钱包交易 ID',
  coin_amount BIGINT NOT NULL COMMENT '到账金币数量',
  currency_code VARCHAR(8) NOT NULL DEFAULT '' COMMENT '商品币种编码',
  amount_micro BIGINT NOT NULL DEFAULT 0 COMMENT '商品金额微单位',
  provider_payload JSON NULL COMMENT 'Google Play 校验返回快照',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  updated_at_ms BIGINT NOT NULL COMMENT '更新时间，UTC epoch ms',
  PRIMARY KEY (app_code, payment_order_id),
  UNIQUE KEY uk_payment_orders_token (app_code, provider, purchase_token_hash),
  UNIQUE KEY uk_payment_orders_command (app_code, command_id),
  KEY idx_payment_orders_user_time (app_code, user_id, created_at_ms),
  KEY idx_payment_orders_provider_order (app_code, provider, provider_order_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='支付订单与 provider 审计表';

CREATE TABLE IF NOT EXISTS coin_seller_stock_records (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  stock_id VARCHAR(96) NOT NULL COMMENT '库存 ID',
  transaction_id VARCHAR(96) NOT NULL COMMENT '钱包交易 ID',
  command_id VARCHAR(128) NOT NULL COMMENT '业务命令幂等 ID',
  seller_user_id BIGINT NOT NULL COMMENT '商户用户 ID',
  stock_type VARCHAR(32) NOT NULL COMMENT '库存类型',
  counts_as_seller_recharge BOOLEAN NOT NULL COMMENT '数量as商户充值',
  coin_amount BIGINT NOT NULL COMMENT '金币数量',
  paid_currency_code VARCHAR(8) NOT NULL DEFAULT '' COMMENT '付款币种编码',
  paid_amount_micro BIGINT NOT NULL DEFAULT 0 COMMENT '付款数量微单位',
  payment_ref VARCHAR(128) NULL COMMENT '支付外部引用',
  evidence_ref VARCHAR(256) NOT NULL DEFAULT '' COMMENT '凭证外部引用',
  operator_user_id BIGINT NOT NULL COMMENT '操作人用户 ID',
  reason VARCHAR(512) NOT NULL DEFAULT '' COMMENT '原因',
  balance_after BIGINT NOT NULL COMMENT '余额后',
  metadata_json JSON NULL COMMENT '扩展元数据 JSON',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  PRIMARY KEY (app_code, stock_id),
  UNIQUE KEY uk_coin_seller_stock_command (app_code, command_id),
  UNIQUE KEY uk_coin_seller_stock_payment_ref (app_code, stock_type, payment_ref),
  KEY idx_coin_seller_stock_seller_time (app_code, seller_user_id, created_at_ms),
  KEY idx_coin_seller_stock_type_time (app_code, stock_type, created_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='金币商户库存记录表';

CREATE TABLE IF NOT EXISTS coin_seller_salary_exchange_rate_tiers (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  region_id BIGINT NOT NULL COMMENT '币商所属区域 ID',
  tier_id BIGINT NOT NULL AUTO_INCREMENT COMMENT '区间 ID',
  min_usd_minor BIGINT NOT NULL COMMENT '起始美元金额，单位美分，包含',
  max_usd_minor BIGINT NOT NULL COMMENT '结束美元金额，单位美分，包含',
  coin_per_usd BIGINT NOT NULL COMMENT '每 1 USD 工资可兑换的币商专用金币数量',
  status VARCHAR(24) NOT NULL DEFAULT 'active' COMMENT '状态：active/disabled',
  sort_order INT NOT NULL DEFAULT 0 COMMENT '排序权重',
  created_by_user_id BIGINT NOT NULL DEFAULT 0 COMMENT '创建人用户 ID',
  updated_by_user_id BIGINT NOT NULL DEFAULT 0 COMMENT '更新人用户 ID',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  updated_at_ms BIGINT NOT NULL COMMENT '更新时间，UTC epoch ms',
  PRIMARY KEY (tier_id),
  KEY idx_coin_seller_salary_rates_region (app_code, region_id, status, min_usd_minor, max_usd_minor),
  KEY idx_coin_seller_salary_rates_sort (app_code, region_id, status, sort_order)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='币商工资兑换比例区间表';

CREATE TABLE IF NOT EXISTS resources (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  resource_id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '资源 ID',
  resource_code VARCHAR(96) NOT NULL COMMENT '资源编码',
  resource_type VARCHAR(32) NOT NULL COMMENT '资源类型',
  name VARCHAR(128) NOT NULL COMMENT '名称',
  status VARCHAR(32) NOT NULL COMMENT '业务状态',
  grantable BOOLEAN NOT NULL DEFAULT TRUE COMMENT '是否允许发放',
  manager_grant_enabled BOOLEAN NOT NULL DEFAULT FALSE COMMENT '管理端是否允许发放',
  grant_strategy VARCHAR(32) NOT NULL COMMENT '发放策略',
  wallet_asset_type VARCHAR(32) NOT NULL DEFAULT '' COMMENT '钱包资产类型',
  wallet_asset_amount BIGINT NOT NULL DEFAULT 0 COMMENT '钱包资产数量',
  price_type VARCHAR(32) NOT NULL DEFAULT '' COMMENT '资源价格类型：coin/free',
  coin_price BIGINT NOT NULL DEFAULT 0 COMMENT '资源金币价格',
  gift_point_amount BIGINT NOT NULL DEFAULT 0 COMMENT '历史字段：GIFT_POINT 已下线，新写入固定 0',
  usage_scope_json JSON NOT NULL COMMENT '使用范围 JSON 配置或快照',
  asset_url VARCHAR(512) NOT NULL DEFAULT '' COMMENT '资产 URL',
  preview_url VARCHAR(512) NOT NULL DEFAULT '' COMMENT '预览 URL',
  animation_url VARCHAR(512) NOT NULL DEFAULT '' COMMENT '动画 URL',
  metadata_json JSON NULL COMMENT '扩展元数据 JSON',
  sort_order INT NOT NULL DEFAULT 0 COMMENT '排序权重，数值越小越靠前',
  created_by_user_id BIGINT NOT NULL DEFAULT 0 COMMENT '创建人用户 ID',
  updated_by_user_id BIGINT NOT NULL DEFAULT 0 COMMENT '更新人用户 ID',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  updated_at_ms BIGINT NOT NULL COMMENT '更新时间，UTC epoch ms',
  UNIQUE KEY uk_resources_code (app_code, resource_code),
  KEY idx_resources_type_status (app_code, resource_type, status, sort_order),
  KEY idx_resources_manager_grant (app_code, manager_grant_enabled, status, grantable, sort_order)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='资源表';

SET @ddl := IF(
  (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'resources' AND COLUMN_NAME = 'manager_grant_enabled') = 0,
  'ALTER TABLE resources ADD COLUMN manager_grant_enabled BOOLEAN NOT NULL DEFAULT FALSE COMMENT ''管理端是否允许发放'' AFTER grantable',
  '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 = 'resources' AND COLUMN_NAME = 'price_type') = 0,
  'ALTER TABLE resources ADD COLUMN price_type VARCHAR(32) NOT NULL DEFAULT '''' COMMENT ''资源价格类型：coin/free'' AFTER wallet_asset_amount',
  '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 = 'resources' AND COLUMN_NAME = 'coin_price') = 0,
  'ALTER TABLE resources ADD COLUMN coin_price BIGINT NOT NULL DEFAULT 0 COMMENT ''资源金币价格'' AFTER price_type',
  '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 = 'resources' AND COLUMN_NAME = 'gift_point_amount') = 0,
  'ALTER TABLE resources ADD COLUMN gift_point_amount BIGINT NOT NULL DEFAULT 0 COMMENT ''历史字段：GIFT_POINT 已下线，新写入固定 0'' AFTER coin_price',
  '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 = 'resources' AND INDEX_NAME = 'idx_resources_manager_grant') = 0,
  'ALTER TABLE resources ADD KEY idx_resources_manager_grant (app_code, manager_grant_enabled, status, grantable, sort_order)',
  'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

CREATE TABLE IF NOT EXISTS resource_groups (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  group_id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '分组 ID',
  group_code VARCHAR(96) NOT NULL COMMENT '分组编码',
  name VARCHAR(128) NOT NULL COMMENT '名称',
  status VARCHAR(32) NOT NULL COMMENT '业务状态',
  description VARCHAR(512) NOT NULL DEFAULT '' COMMENT '描述信息',
  sort_order INT NOT NULL DEFAULT 0 COMMENT '排序权重，数值越小越靠前',
  created_by_user_id BIGINT NOT NULL DEFAULT 0 COMMENT '创建人用户 ID',
  updated_by_user_id BIGINT NOT NULL DEFAULT 0 COMMENT '更新人用户 ID',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  updated_at_ms BIGINT NOT NULL COMMENT '更新时间，UTC epoch ms',
  UNIQUE KEY uk_resource_groups_code (app_code, group_code),
  KEY idx_resource_groups_status (app_code, status, sort_order)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='资源分组表';

CREATE TABLE IF NOT EXISTS resource_group_items (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  group_item_id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '分组明细 ID',
  group_id BIGINT NOT NULL COMMENT '分组 ID',
  item_type VARCHAR(32) NOT NULL DEFAULT 'resource' COMMENT '明细类型',
  resource_id BIGINT NOT NULL DEFAULT 0 COMMENT '资源 ID',
  wallet_asset_type VARCHAR(32) NOT NULL DEFAULT '' COMMENT '钱包资产类型',
  wallet_asset_amount BIGINT NOT NULL DEFAULT 0 COMMENT '钱包资产数量',
  quantity BIGINT NOT NULL DEFAULT 1 COMMENT '数量',
  duration_ms BIGINT NOT NULL DEFAULT 0 COMMENT '持续时长，毫秒',
  sort_order INT 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',
  UNIQUE KEY uk_resource_group_items_member (app_code, group_id, item_type, resource_id, wallet_asset_type),
  KEY idx_resource_group_items_group (app_code, group_id, sort_order)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='资源分组明细表';

CREATE TABLE IF NOT EXISTS resource_shop_items (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  shop_item_id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '道具商店条目 ID',
  resource_id BIGINT NOT NULL COMMENT '售卖资源 ID',
  status VARCHAR(32) NOT NULL COMMENT '业务状态',
  duration_days INT NOT NULL COMMENT '售卖天数，只允许 1/3/7',
  effective_from_ms BIGINT NOT NULL DEFAULT 0 COMMENT '生效开始时间，UTC epoch ms，0 表示立即生效',
  effective_to_ms BIGINT NOT NULL DEFAULT 0 COMMENT '生效结束时间，UTC epoch ms，0 表示长期有效',
  sort_order INT NOT NULL DEFAULT 0 COMMENT '排序权重，数值越小越靠前',
  created_by_user_id BIGINT NOT NULL DEFAULT 0 COMMENT '创建人用户 ID',
  updated_by_user_id BIGINT NOT NULL DEFAULT 0 COMMENT '更新人用户 ID',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  updated_at_ms BIGINT NOT NULL COMMENT '更新时间，UTC epoch ms',
  UNIQUE KEY uk_resource_shop_items_resource (app_code, resource_id),
  KEY idx_resource_shop_items_status_sort (app_code, status, sort_order),
  KEY idx_resource_shop_items_effective (app_code, status, effective_from_ms, effective_to_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='道具商店售卖资源表';

CREATE TABLE IF NOT EXISTS resource_shop_purchase_orders (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  order_id VARCHAR(96) NOT NULL COMMENT '道具商店订单 ID',
  command_id VARCHAR(128) NOT NULL COMMENT 'App 购买命令幂等 ID',
  user_id BIGINT NOT NULL COMMENT '购买用户 ID',
  shop_item_id BIGINT NOT NULL COMMENT '道具商店条目 ID',
  resource_id BIGINT NOT NULL COMMENT '资源 ID',
  duration_days INT NOT NULL COMMENT '购买生效天数，订单快照',
  price_coin BIGINT NOT NULL COMMENT '实扣金币，订单快照',
  status VARCHAR(32) NOT NULL COMMENT '订单状态',
  wallet_transaction_id VARCHAR(96) NOT NULL COMMENT '扣费钱包交易 ID',
  resource_grant_id VARCHAR(96) NOT NULL COMMENT '资源发放 ID',
  entitlement_id VARCHAR(96) NOT NULL COMMENT '最终权益 ID',
  request_hash VARCHAR(128) NOT NULL 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, order_id),
  UNIQUE KEY uk_resource_shop_purchase_command (app_code, command_id),
  KEY idx_resource_shop_purchase_user_time (app_code, user_id, created_at_ms),
  KEY idx_resource_shop_purchase_tx (app_code, wallet_transaction_id),
  KEY idx_resource_shop_purchase_entitlement (app_code, entitlement_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='道具商店购买订单表';

CREATE TABLE IF NOT EXISTS gift_type_configs (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  type_code VARCHAR(32) NOT NULL COMMENT '礼物类型编码，供 gift_configs 引用',
  name VARCHAR(64) NOT NULL COMMENT '后台展示名称',
  tab_key VARCHAR(32) NOT NULL COMMENT 'App 礼物面板 tab 展示 key',
  status VARCHAR(32) NOT NULL DEFAULT 'active' COMMENT 'tab 状态，active 才在 App 面板展示',
  sort_order INT NOT NULL DEFAULT 0 COMMENT 'tab 排序权重，数值越小越靠前',
  created_by_user_id BIGINT NOT NULL DEFAULT 0 COMMENT '创建人用户 ID',
  updated_by_user_id BIGINT NOT NULL DEFAULT 0 COMMENT '更新人用户 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, type_code),
  UNIQUE KEY uk_gift_type_configs_tab_key (app_code, tab_key),
  KEY idx_gift_type_configs_status_sort (app_code, status, sort_order)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='礼物类型和 App 面板 tab 配置表';

CREATE TABLE IF NOT EXISTS gift_configs (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  gift_id VARCHAR(96) NOT NULL COMMENT '礼物 ID',
  resource_id BIGINT NOT NULL COMMENT '资源 ID',
  status VARCHAR(32) NOT NULL COMMENT '业务状态',
  name VARCHAR(128) NOT NULL COMMENT '名称',
  sort_order INT NOT NULL DEFAULT 0 COMMENT '排序权重，数值越小越靠前',
  presentation_json JSON NULL COMMENT '展示配置 JSON 配置或快照',
  gift_type_code VARCHAR(32) NOT NULL DEFAULT 'normal' COMMENT '礼物类型编码',
  effective_from_ms BIGINT NOT NULL DEFAULT 0 COMMENT '生效开始时间，UTC epoch ms',
  effective_to_ms BIGINT NOT NULL DEFAULT 0 COMMENT '生效结束时间，UTC epoch ms',
  effect_types_json JSON NULL COMMENT '礼物特效类型 JSON 配置',
  created_by_user_id BIGINT NOT NULL DEFAULT 0 COMMENT '创建人用户 ID',
  updated_by_user_id BIGINT NOT NULL DEFAULT 0 COMMENT '更新人用户 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, gift_id),
  KEY idx_gift_configs_resource (app_code, resource_id),
  KEY idx_gift_configs_status_sort (app_code, status, sort_order),
  KEY idx_gift_configs_effective (app_code, status, effective_from_ms, effective_to_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='礼物配置表';

SET @ddl := IF(
  (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'wallet_gift_prices' AND COLUMN_NAME = 'charge_asset_type') = 0,
  'ALTER TABLE wallet_gift_prices ADD COLUMN charge_asset_type VARCHAR(32) NOT NULL DEFAULT ''COIN'' COMMENT ''扣费资产类型'' AFTER status',
  '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 = 'gift_configs' AND COLUMN_NAME = 'gift_type_code') = 0,
  'ALTER TABLE gift_configs ADD COLUMN gift_type_code VARCHAR(32) NOT NULL DEFAULT ''normal'' COMMENT ''礼物类型编码'' AFTER presentation_json',
  '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 = 'gift_configs' AND COLUMN_NAME = 'effective_from_ms') = 0,
  'ALTER TABLE gift_configs ADD COLUMN effective_from_ms BIGINT NOT NULL DEFAULT 0 COMMENT ''生效开始时间，UTC epoch ms'' AFTER gift_type_code',
  '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 = 'gift_configs' AND COLUMN_NAME = 'effective_to_ms') = 0,
  'ALTER TABLE gift_configs ADD COLUMN effective_to_ms BIGINT NOT NULL DEFAULT 0 COMMENT ''生效结束时间，UTC epoch ms'' AFTER effective_from_ms',
  '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 = 'gift_configs' AND COLUMN_NAME = 'effect_types_json') = 0,
  'ALTER TABLE gift_configs ADD COLUMN effect_types_json JSON NULL COMMENT ''礼物特效类型 JSON 配置'' AFTER effective_to_ms',
  'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

CREATE TABLE IF NOT EXISTS gift_config_regions (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  gift_id VARCHAR(96) NOT NULL COMMENT '礼物 ID',
  region_id BIGINT NOT NULL COMMENT '区域 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, gift_id, region_id),
  KEY idx_gift_config_regions_region (app_code, region_id, gift_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='礼物配置区域表';

CREATE TABLE IF NOT EXISTS user_gift_wall (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  user_id BIGINT NOT NULL COMMENT '用户 ID',
  gift_id VARCHAR(96) NOT NULL COMMENT '礼物 ID',
  gift_name VARCHAR(128) NOT NULL COMMENT '礼物名称',
  resource_id BIGINT NOT NULL DEFAULT 0 COMMENT '资源 ID',
  resource_snapshot_json JSON NOT NULL COMMENT '资源快照 JSON',
  gift_type_code VARCHAR(32) NOT NULL DEFAULT 'normal' COMMENT '礼物类型编码',
  presentation_json JSON NULL COMMENT '展示配置 JSON 配置或快照',
  gift_count BIGINT NOT NULL DEFAULT 0 COMMENT '礼物数量',
  total_value BIGINT NOT NULL DEFAULT 0 COMMENT '总值',
  total_coin_value BIGINT NOT NULL DEFAULT 0 COMMENT '总金币值',
  total_diamond_value BIGINT NOT NULL DEFAULT 0 COMMENT '总钻石值',
  total_gift_point BIGINT NOT NULL DEFAULT 0 COMMENT '历史字段：GIFT_POINT 已下线，新送礼不再累加',
  total_heat_value BIGINT NOT NULL DEFAULT 0 COMMENT '总热度值',
  charge_asset_type VARCHAR(32) NOT NULL DEFAULT 'COIN' COMMENT '扣费资产类型',
  last_price_version VARCHAR(64) NOT NULL DEFAULT '' COMMENT '最后价格版本',
  first_received_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '首次收到时间，UTC epoch ms',
  last_received_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '最后收到时间，UTC epoch ms',
  sort_order INT 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, user_id, gift_id),
  KEY idx_user_gift_wall_user_sort (app_code, user_id, sort_order, total_value, last_received_at_ms),
  KEY idx_user_gift_wall_gift (app_code, gift_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户礼物墙表';

CREATE TABLE IF NOT EXISTS wallet_projection_events (
  projection_name VARCHAR(64) NOT NULL COMMENT '投影名称',
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  event_id VARCHAR(128) NOT NULL COMMENT '事件幂等 ID',
  status VARCHAR(32) NOT NULL COMMENT '业务状态',
  retry_count INT NOT NULL DEFAULT 0 COMMENT '重试次数',
  locked_by VARCHAR(96) NOT NULL DEFAULT '' COMMENT '当前锁定 worker',
  locked_until_ms BIGINT NOT NULL DEFAULT 0 COMMENT '锁定截止时间，UTC epoch ms',
  last_error TEXT NULL COMMENT '最后一次失败原因',
  processed_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 (projection_name, app_code, event_id),
  KEY idx_wallet_projection_claim (projection_name, app_code, status, locked_until_ms, updated_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='钱包投影事件表';

CREATE TABLE IF NOT EXISTS resource_grants (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  grant_id VARCHAR(96) NOT NULL COMMENT '发放 ID',
  command_id VARCHAR(128) NOT NULL COMMENT '业务命令幂等 ID',
  target_user_id BIGINT NOT NULL COMMENT '目标用户 ID',
  grant_source VARCHAR(32) NOT NULL COMMENT '发放来源',
  grant_subject_type VARCHAR(32) NOT NULL COMMENT '发放主体类型',
  grant_subject_id VARCHAR(96) NOT NULL COMMENT '发放主体 ID',
  status VARCHAR(32) NOT NULL COMMENT '业务状态',
  request_hash VARCHAR(128) NOT NULL COMMENT '请求哈希值',
  group_snapshot_json JSON NULL COMMENT '资源分组快照 JSON',
  reason VARCHAR(256) NOT NULL COMMENT '原因',
  operator_user_id BIGINT NOT NULL COMMENT '操作人用户 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, grant_id),
  UNIQUE KEY uk_resource_grants_command (app_code, command_id),
  KEY idx_resource_grants_target_time (app_code, target_user_id, created_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='资源发放表';

CREATE TABLE IF NOT EXISTS resource_grant_items (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  grant_item_id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '发放明细 ID',
  grant_id VARCHAR(96) NOT NULL COMMENT '发放 ID',
  resource_id BIGINT NOT NULL COMMENT '资源 ID',
  resource_snapshot_json JSON NOT NULL COMMENT '资源快照 JSON',
  quantity BIGINT NOT NULL DEFAULT 1 COMMENT '数量',
  duration_ms BIGINT NOT NULL DEFAULT 0 COMMENT '持续时长，毫秒',
  result_type VARCHAR(32) NOT NULL COMMENT '结果类型',
  wallet_transaction_id VARCHAR(96) NOT NULL DEFAULT '' COMMENT '钱包交易 ID',
  entitlement_id VARCHAR(96) NOT NULL DEFAULT '' COMMENT '权益 ID',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  KEY idx_resource_grant_items_grant (app_code, grant_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='资源发放明细表';

CREATE TABLE IF NOT EXISTS user_resource_entitlements (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  entitlement_id VARCHAR(96) NOT NULL COMMENT '权益 ID',
  user_id BIGINT NOT NULL COMMENT '用户 ID',
  resource_id BIGINT NOT NULL COMMENT '资源 ID',
  status VARCHAR(32) NOT NULL COMMENT '业务状态',
  quantity BIGINT NOT NULL DEFAULT 1 COMMENT '数量',
  remaining_quantity BIGINT NOT NULL DEFAULT 1 COMMENT '剩余数量',
  effective_at_ms BIGINT NOT NULL COMMENT '生效时间，UTC epoch ms',
  expires_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '过期时间，UTC epoch ms',
  source_grant_id VARCHAR(96) NOT NULL COMMENT '来源发放 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, entitlement_id),
  KEY idx_user_resource_active (app_code, user_id, resource_id, status, expires_at_ms),
  KEY idx_user_resource_user_type (app_code, user_id, status, updated_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户资源权益表';

CREATE TABLE IF NOT EXISTS user_resource_equipment (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  user_id BIGINT NOT NULL COMMENT '用户 ID',
  resource_type VARCHAR(32) NOT NULL COMMENT '资源类型',
  entitlement_id VARCHAR(96) NOT NULL COMMENT '权益 ID',
  resource_id BIGINT NOT NULL COMMENT '资源 ID',
  updated_at_ms BIGINT NOT NULL COMMENT '更新时间，UTC epoch ms',
  PRIMARY KEY (app_code, user_id, resource_type, entitlement_id),
  KEY idx_user_resource_equipment_user (app_code, user_id, updated_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户资源装备表';

CREATE TABLE IF NOT EXISTS wallet_diamond_exchange_rules (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  rule_id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '规则 ID',
  exchange_type VARCHAR(32) NOT NULL COMMENT '兑换类型',
  status VARCHAR(32) NOT NULL COMMENT '业务状态',
  from_asset_type VARCHAR(32) NOT NULL DEFAULT 'DIAMOND' COMMENT '源资产类型',
  to_asset_type VARCHAR(32) NOT NULL COMMENT '目标资产类型',
  from_amount BIGINT NOT NULL COMMENT '源数量',
  to_amount BIGINT NOT NULL COMMENT '目标数量',
  sort_order INT 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',
  UNIQUE KEY uk_diamond_exchange_rule (app_code, exchange_type, from_amount, to_asset_type),
  KEY idx_diamond_exchange_active (app_code, status, sort_order)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='钱包钻石兑换规则表';

CREATE TABLE IF NOT EXISTS gift_diamond_ratio_configs (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  region_id BIGINT NOT NULL DEFAULT 0 COMMENT '房间可见区域，0 表示全局默认',
  gift_type_code VARCHAR(32) NOT NULL COMMENT '礼物类型编码',
  status VARCHAR(32) NOT NULL DEFAULT 'active' COMMENT '业务状态',
  ratio_percent DECIMAL(5,2) NOT NULL DEFAULT 100.00 COMMENT '房间贡献热度和主播周期钻石入账比例，百分比',
  created_by_admin_id BIGINT NOT NULL DEFAULT 0 COMMENT '创建后台用户 ID',
  updated_by_admin_id BIGINT NOT NULL DEFAULT 0 COMMENT '更新后台用户 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, region_id, gift_type_code),
  KEY idx_gift_diamond_ratio_region (app_code, region_id, status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='礼物钻石和房间贡献比例配置表';

CREATE TABLE IF NOT EXISTS red_packet_configs (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  enabled BOOLEAN NOT NULL DEFAULT FALSE COMMENT '是否启用红包',
  delayed_open_seconds INT NOT NULL DEFAULT 0 COMMENT '延迟红包打开秒数',
  expire_seconds INT NOT NULL DEFAULT 86400 COMMENT '红包过期秒数，房内红包固定 24 小时',
  daily_send_limit INT NOT NULL DEFAULT 0 COMMENT '每用户 UTC 日发送上限，0 表示禁止发送',
  rule_url VARCHAR(512) NOT NULL DEFAULT '' COMMENT '红包规则说明链接',
  updated_by_admin_id BIGINT NOT NULL DEFAULT 0 COMMENT '最后更新后台用户 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)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='红包配置主表';

SET @ddl := IF(
  (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'red_packet_configs' AND COLUMN_NAME = 'rule_url') = 0,
  'ALTER TABLE red_packet_configs ADD COLUMN rule_url VARCHAR(512) NOT NULL DEFAULT '''' COMMENT ''红包规则说明链接'' AFTER daily_send_limit',
  'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

CREATE TABLE IF NOT EXISTS red_packet_count_tiers (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  tier_id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '数量档位 ID',
  packet_count INT NOT NULL COMMENT '红包数量',
  status VARCHAR(32) NOT NULL DEFAULT 'active' COMMENT '业务状态',
  sort_order INT 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',
  UNIQUE KEY uk_red_packet_count_tier (app_code, packet_count),
  KEY idx_red_packet_count_tier_status (app_code, status, sort_order)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='红包数量档位表';

CREATE TABLE IF NOT EXISTS red_packet_amount_tiers (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  tier_id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '金额档位 ID',
  total_amount BIGINT NOT NULL COMMENT '红包总金币金额',
  status VARCHAR(32) NOT NULL DEFAULT 'active' COMMENT '业务状态',
  sort_order INT 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',
  UNIQUE KEY uk_red_packet_amount_tier (app_code, total_amount),
  KEY idx_red_packet_amount_tier_status (app_code, status, sort_order)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='红包金额档位表';

CREATE TABLE IF NOT EXISTS red_packets (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  packet_id VARCHAR(96) NOT NULL COMMENT '红包 ID',
  command_id VARCHAR(128) NOT NULL COMMENT '发红包命令幂等 ID',
  sender_user_id BIGINT NOT NULL COMMENT '发送者用户 ID',
  room_id VARCHAR(96) NOT NULL COMMENT '房间 ID',
  region_id BIGINT NOT NULL COMMENT '房间区域 ID',
  packet_type VARCHAR(32) NOT NULL COMMENT '红包类型：normal/delayed',
  total_amount BIGINT NOT NULL COMMENT '红包总金币金额',
  packet_count INT NOT NULL COMMENT '红包份数',
  remaining_amount BIGINT NOT NULL COMMENT '剩余未领取金币金额',
  remaining_count INT NOT NULL COMMENT '剩余未领取份数',
  status VARCHAR(32) NOT NULL COMMENT '业务状态',
  open_at_ms BIGINT NOT NULL COMMENT '可领取时间，UTC epoch ms',
  expires_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, packet_id),
  UNIQUE KEY uk_red_packets_command (app_code, command_id),
  KEY idx_red_packets_room_time (app_code, room_id, created_at_ms),
  KEY idx_red_packets_sender_time (app_code, sender_user_id, created_at_ms),
  KEY idx_red_packets_expire (app_code, status, expires_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='红包主表';

CREATE TABLE IF NOT EXISTS red_packet_allocations (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  packet_id VARCHAR(96) NOT NULL COMMENT '红包 ID',
  allocation_no INT NOT NULL COMMENT '份额序号',
  amount BIGINT NOT NULL COMMENT '份额金币金额',
  status VARCHAR(32) NOT NULL COMMENT '份额状态',
  claimed_by_user_id BIGINT NOT NULL DEFAULT 0 COMMENT '领取用户 ID',
  claim_id VARCHAR(96) NOT NULL DEFAULT '' COMMENT '领取记录 ID',
  claimed_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, packet_id, allocation_no),
  KEY idx_red_packet_alloc_claimable (app_code, packet_id, status, allocation_no),
  KEY idx_red_packet_alloc_user (app_code, claimed_by_user_id, claimed_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='红包随机份额表';

CREATE TABLE IF NOT EXISTS red_packet_claims (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  claim_id VARCHAR(96) NOT NULL COMMENT '领取记录 ID',
  command_id VARCHAR(128) NOT NULL COMMENT '抢红包命令幂等 ID',
  packet_id VARCHAR(96) NOT NULL COMMENT '红包 ID',
  user_id BIGINT NOT NULL COMMENT '领取用户 ID',
  amount BIGINT NOT NULL COMMENT '领取金币金额',
  wallet_transaction_id VARCHAR(96) NOT NULL COMMENT '钱包交易 ID',
  status VARCHAR(32) NOT NULL COMMENT '业务状态',
  failure_reason VARCHAR(64) 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, claim_id),
  UNIQUE KEY uk_red_packet_claim_command (app_code, command_id),
  UNIQUE KEY uk_red_packet_claim_user (app_code, packet_id, user_id),
  KEY idx_red_packet_claim_packet (app_code, packet_id, created_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='红包领取记录表';

CREATE TABLE IF NOT EXISTS red_packet_refunds (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  refund_id VARCHAR(96) NOT NULL COMMENT '退款记录 ID',
  command_id VARCHAR(128) NOT NULL COMMENT '退款命令幂等 ID',
  packet_id VARCHAR(96) NOT NULL COMMENT '红包 ID',
  sender_user_id BIGINT NOT NULL COMMENT '发送者用户 ID',
  refund_amount BIGINT NOT NULL COMMENT '退款金币金额',
  wallet_transaction_id VARCHAR(96) NOT NULL COMMENT '钱包交易 ID',
  status VARCHAR(32) NOT NULL 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, refund_id),
  UNIQUE KEY uk_red_packet_refund_command (app_code, command_id),
  UNIQUE KEY uk_red_packet_refund_packet (app_code, packet_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='红包过期退款记录表';

CREATE TABLE IF NOT EXISTS red_packet_user_daily_counters (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  user_id BIGINT NOT NULL COMMENT '用户 ID',
  send_day CHAR(10) NOT NULL COMMENT 'UTC 日期，YYYY-MM-DD',
  sent_count INT NOT NULL 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, user_id, send_day)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='红包用户每日发送计数表';

CREATE TABLE IF NOT EXISTS vip_levels (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  level INT NOT NULL COMMENT '等级',
  name VARCHAR(64) NOT NULL COMMENT '名称',
  status VARCHAR(32) NOT NULL COMMENT '业务状态',
  price_coin BIGINT NOT NULL COMMENT 'VIP 价格金币数',
  duration_ms BIGINT NOT NULL COMMENT '持续时长，毫秒',
  reward_resource_group_id BIGINT NOT NULL DEFAULT 0 COMMENT '奖励资源分组 ID',
  required_recharge_coin_amount BIGINT NOT NULL DEFAULT 0 COMMENT '购买所需累计充值金币，1-5 级固定为 0，6-10 级必须配置',
  sort_order INT 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, level),
  KEY idx_vip_levels_status_sort (app_code, status, sort_order)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='VIP 等级表';

SET @ddl := IF(
  (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'vip_levels' AND COLUMN_NAME = 'required_recharge_coin_amount') = 0,
  'ALTER TABLE vip_levels ADD COLUMN required_recharge_coin_amount BIGINT NOT NULL DEFAULT 0 COMMENT ''购买所需累计充值金币，1-5 级固定为 0，6-10 级必须配置'' AFTER reward_resource_group_id',
  'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

CREATE TABLE IF NOT EXISTS user_vip_memberships (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  user_id BIGINT NOT NULL COMMENT '用户 ID',
  level INT NOT NULL COMMENT '等级',
  name VARCHAR(64) NOT NULL DEFAULT '' COMMENT '名称',
  status VARCHAR(32) NOT NULL COMMENT '业务状态',
  started_at_ms BIGINT NOT NULL DEFAULT 0 COMMENT '开始时间，UTC epoch ms',
  expires_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, user_id),
  KEY idx_user_vip_expiry (app_code, status, expires_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户 VIP 成员关系表';

CREATE TABLE IF NOT EXISTS vip_purchase_orders (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  order_id VARCHAR(96) NOT NULL COMMENT '订单 ID',
  command_id VARCHAR(128) NOT NULL COMMENT '业务命令幂等 ID',
  user_id BIGINT NOT NULL COMMENT '用户 ID',
  target_level INT NOT NULL COMMENT '目标等级',
  previous_level INT NOT NULL COMMENT '原等级',
  price_coin BIGINT NOT NULL COMMENT 'VIP 价格金币数',
  status VARCHAR(32) NOT NULL COMMENT '业务状态',
  wallet_transaction_id VARCHAR(96) NOT NULL COMMENT '钱包交易 ID',
  resource_grant_id VARCHAR(96) NOT NULL DEFAULT '' COMMENT '资源发放 ID',
  request_hash VARCHAR(128) NOT NULL 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, order_id),
  UNIQUE KEY uk_vip_purchase_command (app_code, command_id),
  KEY idx_vip_purchase_user_time (app_code, user_id, created_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='VIP 购买订单表';

CREATE TABLE IF NOT EXISTS user_vip_history (
  app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码，用于多租户隔离',
  history_id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '历史 ID',
  user_id BIGINT NOT NULL COMMENT '用户 ID',
  action VARCHAR(32) NOT NULL COMMENT '操作',
  previous_level INT NOT NULL COMMENT '原等级',
  new_level INT NOT NULL COMMENT '新等级',
  order_id VARCHAR(96) NOT NULL DEFAULT '' COMMENT '订单 ID',
  created_at_ms BIGINT NOT NULL COMMENT '创建时间，UTC epoch ms',
  KEY idx_user_vip_history_user_time (app_code, user_id, created_at_ms)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户 VIP 历史表';

INSERT IGNORE INTO vip_levels (
  app_code, level, name, status, price_coin, duration_ms, reward_resource_group_id, required_recharge_coin_amount,
  sort_order, created_at_ms, updated_at_ms
) VALUES
  ('lalu', 1, 'VIP1', 'active', 1000, 604800000, 0, 0, 10, 0, 0),
  ('lalu', 2, 'VIP2', 'active', 3000, 604800000, 0, 0, 20, 0, 0),
  ('lalu', 3, 'VIP3', 'active', 8000, 604800000, 0, 0, 30, 0, 0),
  ('lalu', 4, 'VIP4', 'disabled', 0, 604800000, 0, 0, 40, 0, 0),
  ('lalu', 5, 'VIP5', 'disabled', 0, 604800000, 0, 0, 50, 0, 0),
  ('lalu', 6, 'VIP6', 'disabled', 0, 604800000, 0, 0, 60, 0, 0),
  ('lalu', 7, 'VIP7', 'disabled', 0, 604800000, 0, 0, 70, 0, 0),
  ('lalu', 8, 'VIP8', 'disabled', 0, 604800000, 0, 0, 80, 0, 0),
  ('lalu', 9, 'VIP9', 'disabled', 0, 604800000, 0, 0, 90, 0, 0),
  ('lalu', 10, 'VIP10', 'disabled', 0, 604800000, 0, 0, 100, 0, 0);

INSERT IGNORE INTO gift_type_configs (
  app_code, type_code, name, tab_key, status, sort_order,
  created_by_user_id, updated_by_user_id, created_at_ms, updated_at_ms
) VALUES
  ('lalu', 'normal', '普通礼物', 'Gift', 'active', 10, 0, 0, 0, 0),
  ('lalu', 'cp', 'CP礼物', 'CP', 'active', 20, 0, 0, 0, 0),
  ('lalu', 'lucky', '幸运礼物', 'Lucky', 'active', 30, 0, 0, 0, 0),
  ('lalu', 'super_lucky', '超级幸运礼物', 'Super Lucky', 'active', 40, 0, 0, 0, 0),
  ('lalu', 'exclusive', '专属礼物', 'Exclusive', 'active', 50, 0, 0, 0, 0),
  ('lalu', 'noble', '贵族礼物', 'Noble', 'active', 60, 0, 0, 0, 0),
  ('lalu', 'flag', '国旗礼物', 'Flag', 'active', 70, 0, 0, 0, 0),
  ('lalu', 'activity', '活动礼物', 'Activity', 'active', 80, 0, 0, 0, 0),
  ('lalu', 'magic', '魔法礼物', 'Magic', 'active', 90, 0, 0, 0, 0),
  ('lalu', 'custom', '定制礼物', 'Custom', 'active', 100, 0, 0, 0, 0);

INSERT IGNORE INTO gift_diamond_ratio_configs (
  app_code, region_id, gift_type_code, status, ratio_percent,
  created_by_admin_id, updated_by_admin_id, created_at_ms, updated_at_ms
) VALUES
  ('lalu', 0, 'normal', 'active', 100.00, 0, 0, 0, 0),
  ('lalu', 0, 'lucky', 'active', 10.00, 0, 0, 0, 0),
  ('lalu', 0, 'super_lucky', 'active', 1.00, 0, 0, 0, 0);
