CREATE DATABASE IF NOT EXISTS lifanghe_education DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE lifanghe_education;

CREATE TABLE IF NOT EXISTS roles (
  role VARCHAR(40) PRIMARY KEY,
  name VARCHAR(80) NOT NULL,
  permissions JSON NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE IF NOT EXISTS users (
  id VARCHAR(40) PRIMARY KEY,
  username VARCHAR(80) NOT NULL UNIQUE,
  password_hash CHAR(64) NULL,
  role VARCHAR(40) NOT NULL,
  role_name VARCHAR(80) NOT NULL,
  name VARCHAR(80) NOT NULL,
  phone VARCHAR(30) NULL UNIQUE,
  wechat_openid VARCHAR(80) NULL UNIQUE,
  wechat_unionid VARCHAR(80) NULL UNIQUE,
  wechat_nickname VARCHAR(80) NULL,
  wechat_avatar VARCHAR(500) NULL,
  login_provider VARCHAR(30) NOT NULL DEFAULT 'password',
  phone_bound TINYINT(1) NOT NULL DEFAULT 1,
  phone_bound_at VARCHAR(32) NULL,
  wechat_bound_at VARCHAR(32) NULL,
  status VARCHAR(20) NOT NULL DEFAULT 'active',
  last_login_at VARCHAR(32) NULL,
  inviter_code VARCHAR(40) NULL UNIQUE,
  child_id VARCHAR(40) NULL,
  child_name VARCHAR(80) NULL,
  child_grade VARCHAR(40) NULL,
  child_focus VARCHAR(80) NULL,
  trial_booking_limit INT NOT NULL DEFAULT 1,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  INDEX idx_users_role (role),
  INDEX idx_users_phone (phone),
  INDEX idx_users_login_provider (login_provider),
  CONSTRAINT fk_users_role FOREIGN KEY (role) REFERENCES roles(role)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE IF NOT EXISTS point_accounts (
  user_id VARCHAR(40) PRIMARY KEY,
  available INT NOT NULL DEFAULT 0,
  pending INT NOT NULL DEFAULT 0,
  frozen INT NOT NULL DEFAULT 0,
  expiring INT NOT NULL DEFAULT 0,
  CONSTRAINT fk_point_accounts_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE IF NOT EXISTS point_transactions (
  id VARCHAR(40) PRIMARY KEY,
  user_id VARCHAR(40) NOT NULL,
  title VARCHAR(200) NOT NULL,
  amount INT NOT NULL,
  status VARCHAR(30) NOT NULL,
  reference_type VARCHAR(40) NULL,
  reference_id VARCHAR(60) NULL,
  created_at VARCHAR(32) NOT NULL,
  INDEX idx_point_transactions_user (user_id),
  INDEX idx_point_transactions_reference (reference_type, reference_id),
  CONSTRAINT fk_point_transactions_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE IF NOT EXISTS point_expiry_rule (
  id INT PRIMARY KEY DEFAULT 1,
  title VARCHAR(100) NOT NULL,
  valid_days INT NOT NULL,
  description VARCHAR(500) NOT NULL,
  reminder VARCHAR(500) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE IF NOT EXISTS point_expiry_schedules (
  id VARCHAR(40) PRIMARY KEY,
  user_id VARCHAR(40) NOT NULL,
  points INT NOT NULL,
  expire_at VARCHAR(32) NOT NULL,
  source VARCHAR(200) NOT NULL,
  INDEX idx_point_expiry_user (user_id),
  CONSTRAINT fk_point_expiry_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE IF NOT EXISTS referral_rules (
  event VARCHAR(40) PRIMARY KEY,
  title VARCHAR(100) NOT NULL,
  inviter INT NOT NULL,
  invitee INT NOT NULL,
  sort_order INT NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE IF NOT EXISTS referrals (
  id VARCHAR(40) PRIMARY KEY,
  inviter_id VARCHAR(40) NOT NULL,
  invitee_id VARCHAR(40) NULL,
  name VARCHAR(80) NOT NULL,
  phone VARCHAR(30) NOT NULL,
  child_grade VARCHAR(40) NOT NULL,
  status VARCHAR(40) NOT NULL,
  reward INT NOT NULL DEFAULT 0,
  channel VARCHAR(80) NOT NULL,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  INDEX idx_referrals_inviter (inviter_id),
  CONSTRAINT fk_referrals_inviter FOREIGN KEY (inviter_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE IF NOT EXISTS courses (
  id VARCHAR(40) PRIMARY KEY,
  name VARCHAR(120) NOT NULL,
  tags JSON NOT NULL,
  next_time VARCHAR(32) NOT NULL,
  points_back INT NOT NULL DEFAULT 0,
  seats INT NOT NULL DEFAULT 0,
  campus VARCHAR(80) NOT NULL,
  teacher VARCHAR(80) NOT NULL,
  trial_minutes INT NOT NULL DEFAULT 45,
  status VARCHAR(30) NOT NULL DEFAULT 'active',
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE IF NOT EXISTS appointments (
  id VARCHAR(40) PRIMARY KEY,
  user_id VARCHAR(40) NOT NULL,
  child_id VARCHAR(40) NULL,
  course_id VARCHAR(40) NOT NULL,
  status VARCHAR(30) NOT NULL,
  created_at VARCHAR(40) NOT NULL,
  INDEX idx_appointments_user (user_id),
  INDEX idx_appointments_course (course_id),
  CONSTRAINT fk_appointments_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
  CONSTRAINT fk_appointments_course FOREIGN KEY (course_id) REFERENCES courses(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE IF NOT EXISTS rewards (
  id VARCHAR(40) PRIMARY KEY,
  name VARCHAR(120) NOT NULL,
  cost INT NOT NULL,
  type VARCHAR(60) NOT NULL,
  stock INT NOT NULL DEFAULT 0,
  description VARCHAR(500) NOT NULL DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE IF NOT EXISTS redemption_orders (
  id VARCHAR(40) PRIMARY KEY,
  user_id VARCHAR(40) NOT NULL,
  item_id VARCHAR(40) NOT NULL,
  status VARCHAR(40) NOT NULL,
  cost_points INT NOT NULL DEFAULT 0,
  voucher_code VARCHAR(60) NULL UNIQUE,
  voucher_status VARCHAR(40) NOT NULL DEFAULT 'not_issued',
  created_at VARCHAR(40) NOT NULL,
  reviewed_by VARCHAR(40) NULL,
  reviewed_at VARCHAR(40) NULL,
  rejected_reason VARCHAR(255) NULL,
  expire_at VARCHAR(40) NULL,
  used_at VARCHAR(40) NULL,
  used_by VARCHAR(40) NULL,
  verify_note VARCHAR(255) NULL,
  INDEX idx_redemption_user (user_id),
  INDEX idx_redemption_status (status),
  INDEX idx_redemption_voucher (voucher_code),
  CONSTRAINT fk_redemption_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
  CONSTRAINT fk_redemption_reward FOREIGN KEY (item_id) REFERENCES rewards(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE IF NOT EXISTS leads (
  id VARCHAR(40) PRIMARY KEY,
  referral_id VARCHAR(40) NULL,
  invitee_id VARCHAR(40) NULL,
  parent VARCHAR(80) NOT NULL,
  source VARCHAR(100) NOT NULL,
  stage VARCHAR(40) NOT NULL,
  advisor VARCHAR(80) NOT NULL,
  risk VARCHAR(40) NOT NULL DEFAULT '正常',
  channel VARCHAR(80) NOT NULL,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  INDEX idx_leads_referral (referral_id),
  INDEX idx_leads_invitee (invitee_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE IF NOT EXISTS channel_stats (
  channel VARCHAR(80) PRIMARY KEY,
  leads INT NOT NULL DEFAULT 0,
  attended INT NOT NULL DEFAULT 0,
  purchased INT NOT NULL DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

INSERT INTO roles (role, name, permissions) VALUES
('parent', '家长', JSON_ARRAY()),
('super_admin', '超级管理员', JSON_ARRAY('*:*:*')),
('campus_admin', '校区管理员', JSON_ARRAY('dashboard:overview:view', 'system:user:view', 'system:role:view', 'leads:referral:view', 'leads:referral:advance', 'points:account:view', 'points:rule:edit', 'points:redemption:view', 'points:redemption:review', 'points:voucher:verify', 'courses:trial:view', 'courses:trial:add', 'courses:trial:edit', 'statistics:channel:view')),
('advisor', '课程顾问', JSON_ARRAY('dashboard:overview:view', 'leads:referral:view', 'leads:referral:advance', 'courses:trial:view', 'points:account:view', 'points:redemption:view')),
('teacher', '老师', JSON_ARRAY('dashboard:overview:view', 'leads:referral:view', 'courses:trial:view')),
('finance', '财务', JSON_ARRAY('dashboard:overview:view', 'points:account:view', 'points:account:adjust', 'points:rule:edit', 'points:reward:edit', 'points:redemption:view', 'points:redemption:review', 'points:voucher:verify', 'statistics:channel:view'))
ON DUPLICATE KEY UPDATE name = VALUES(name), permissions = VALUES(permissions);

INSERT INTO users (
  id, username, password_hash, role, role_name, name, phone,
  wechat_openid, wechat_unionid, wechat_nickname, wechat_avatar,
  login_provider, phone_bound, phone_bound_at, wechat_bound_at,
  status, last_login_at, inviter_code, child_id, child_name, child_grade, child_focus
) VALUES
('admin_001', 'admin', '240be518fabd2724ddb6f04eeb1da5967448d7e831c08c8fa822809f74c720a9', 'super_admin', '超级管理员', '系统管理员', '13800009999', NULL, NULL, NULL, NULL, 'password', 1, NULL, NULL, 'active', NULL, NULL, NULL, NULL, NULL, NULL)
ON DUPLICATE KEY UPDATE username = VALUES(username), password_hash = VALUES(password_hash), role = VALUES(role), role_name = VALUES(role_name), name = VALUES(name), phone = VALUES(phone), login_provider = VALUES(login_provider), phone_bound = VALUES(phone_bound), status = VALUES(status);

INSERT INTO point_expiry_rule (id, title, valid_days, description, reminder) VALUES
(1, '积分有效期说明', 180, '积分自实际到账日起 180 天内有效，仅可兑换课程、测评和学习服务权益，不可提现或转赠。', '系统会在到期前 30 天进入“将过期”口径，运营可通过积分管理页提醒家长尽快兑换。')
ON DUPLICATE KEY UPDATE title = VALUES(title), valid_days = VALUES(valid_days), description = VALUES(description), reminder = VALUES(reminder);

INSERT INTO referral_rules (event, title, inviter, invitee, sort_order) VALUES
('registered', '新家长注册', 20, 20, 1),
('booked', '预约试听', 50, 50, 2),
('attended', '确认到课', 150, 100, 3),
('purchased', '报名正价课', 800, 500, 4)
ON DUPLICATE KEY UPDATE title = VALUES(title), inviter = VALUES(inviter), invitee = VALUES(invitee), sort_order = VALUES(sort_order);

INSERT INTO rewards (id, name, cost, type, stock, description) VALUES
('reward_001', '精品体验课 1 次', 800, '课程权益', 30, '适用于校区公开试听课，审核通过后生成课程券码，30 天内到店核销。'),
('reward_002', '学习规划咨询', 500, '服务权益', 50, '由课程顾问提供一次学习规划沟通，适合新生测评后使用。'),
('reward_003', '正价课抵扣券 100 元', 1000, '抵扣券', 20, '报名正价课程时抵扣 100 元，不可叠加现金活动使用。'),
('reward_004', '阶段测评报告', 300, '测评', 80, '兑换后安排一次阶段测评报告解读，帮助家长了解学习状态。')
ON DUPLICATE KEY UPDATE name = VALUES(name), cost = VALUES(cost), type = VALUES(type), stock = VALUES(stock), description = VALUES(description);
