-- ============================================================
-- EchoChat 数据库初始化脚本
-- 包含模块：auth（用户认证）、contact（联系人）、im（即时通讯）、group（群聊）
-- ============================================================

-- ============================================================
-- auth_users: 用户主表
-- 存储系统所有用户（包括普通用户和管理员），通过角色表区分权限
-- ============================================================
CREATE TABLE auth_users (
    id              BIGSERIAL PRIMARY KEY,
    username        VARCHAR(50)  UNIQUE NOT NULL,
    email           VARCHAR(100) UNIQUE NOT NULL,
    password_hash   VARCHAR(255) NOT NULL,
    nickname        VARCHAR(50)  NOT NULL DEFAULT '',
    avatar          VARCHAR(500) NOT NULL DEFAULT '',
    gender          SMALLINT     NOT NULL DEFAULT 0,
    phone           VARCHAR(20)  DEFAULT NULL,
    status          SMALLINT     NOT NULL DEFAULT 1,
    last_login_at   TIMESTAMP(0) DEFAULT NULL,
    last_login_ip   VARCHAR(50)  DEFAULT NULL,
    created_at      TIMESTAMP(0) NOT NULL DEFAULT NOW(),
    updated_at      TIMESTAMP(0) NOT NULL DEFAULT NOW()
);

COMMENT ON TABLE  auth_users                IS '用户主表，存储所有用户信息（普通用户与管理员共用）';
COMMENT ON COLUMN auth_users.id             IS '用户唯一标识，自增主键';
COMMENT ON COLUMN auth_users.username       IS '用户名，全局唯一，用于登录';
COMMENT ON COLUMN auth_users.email          IS '邮箱地址，全局唯一，用于登录和通知';
COMMENT ON COLUMN auth_users.password_hash  IS '密码哈希值，使用 bcrypt 加密存储';
COMMENT ON COLUMN auth_users.nickname       IS '用户昵称，用于前端显示';
COMMENT ON COLUMN auth_users.avatar         IS '头像 URL 地址';
COMMENT ON COLUMN auth_users.gender         IS '性别：0=未知，1=男，2=女';
COMMENT ON COLUMN auth_users.phone          IS '手机号码，可选';
COMMENT ON COLUMN auth_users.status         IS '账号状态：1=正常，2=禁用（管理员封禁），3=注销（用户主动注销）';
COMMENT ON COLUMN auth_users.last_login_at  IS '最后一次登录时间';
COMMENT ON COLUMN auth_users.last_login_ip  IS '最后一次登录 IP 地址';
COMMENT ON COLUMN auth_users.created_at     IS '账号创建时间';
COMMENT ON COLUMN auth_users.updated_at     IS '信息最后更新时间';

-- ============================================================
-- auth_roles: 角色表
-- 系统预置角色，用于 RBAC 权限控制
-- ============================================================
CREATE TABLE auth_roles (
    id          SERIAL PRIMARY KEY,
    code        VARCHAR(50) UNIQUE NOT NULL,
    name        VARCHAR(50) NOT NULL,
    level       INT NOT NULL DEFAULT 100,
    description VARCHAR(200) DEFAULT '',
    created_at  TIMESTAMP(0) NOT NULL DEFAULT NOW()
);

COMMENT ON TABLE  auth_roles             IS '角色表，定义系统中所有角色类型';
COMMENT ON COLUMN auth_roles.id          IS '角色唯一标识，自增主键';
COMMENT ON COLUMN auth_roles.code        IS '角色代码，唯一标识：user=普通用户，admin=管理员，super_admin=超级管理员';
COMMENT ON COLUMN auth_roles.name        IS '角色显示名称，如"普通用户""管理员""超级管理员"';
COMMENT ON COLUMN auth_roles.level       IS '角色等级，值越小权限越高：1=超管, 10=管理员, 100=普通用户，预留间隔便于扩展';
COMMENT ON COLUMN auth_roles.description IS '角色描述说明';
COMMENT ON COLUMN auth_roles.created_at  IS '创建时间';

-- 预置角色数据（level 值越小权限越高）
INSERT INTO auth_roles (code, name, level, description) VALUES
    ('user',        '普通用户',   100, '系统普通用户，可以使用聊天、会议等功能'),
    ('admin',       '管理员',     10,  '后台管理员，可以管理用户、监控会议等'),
    ('super_admin', '超级管理员', 1,   '最高权限管理员，可以管理角色和系统配置');

-- ============================================================
-- auth_user_roles: 用户角色关联表
-- 多对多关系，一个用户可拥有多个角色
-- ============================================================
CREATE TABLE auth_user_roles (
    user_id    BIGINT NOT NULL REFERENCES auth_users(id),
    role_id    INT    NOT NULL REFERENCES auth_roles(id),
    created_at TIMESTAMP(0) NOT NULL DEFAULT NOW(),
    PRIMARY KEY (user_id, role_id)
);

COMMENT ON TABLE  auth_user_roles            IS '用户角色关联表，建立用户与角色的多对多关系';
COMMENT ON COLUMN auth_user_roles.user_id    IS '关联的用户 ID';
COMMENT ON COLUMN auth_user_roles.role_id    IS '关联的角色 ID';
COMMENT ON COLUMN auth_user_roles.created_at IS '角色分配时间';

-- ============================================================
-- auth_oauth_accounts: 第三方登录账号绑定表
-- 存储微信/QQ 等 OAuth 账号与本地 auth_users 的绑定关系
-- ============================================================
CREATE TABLE auth_oauth_accounts (
    id            BIGSERIAL PRIMARY KEY,
    user_id       BIGINT       NOT NULL REFERENCES auth_users(id),
    provider      VARCHAR(20)  NOT NULL,
    open_id       VARCHAR(128) NOT NULL,
    union_id      VARCHAR(128) NOT NULL DEFAULT '',
    nickname      VARCHAR(100) NOT NULL DEFAULT '',
    avatar        VARCHAR(500) NOT NULL DEFAULT '',
    access_token  VARCHAR(1024) NOT NULL DEFAULT '',
    refresh_token VARCHAR(1024) NOT NULL DEFAULT '',
    expires_at    TIMESTAMP(0) DEFAULT NULL,
    created_at    TIMESTAMP(0) NOT NULL DEFAULT NOW(),
    updated_at    TIMESTAMP(0) NOT NULL DEFAULT NOW(),
    UNIQUE (provider, open_id)
);

COMMENT ON TABLE  auth_oauth_accounts               IS '第三方登录账号绑定表';
COMMENT ON COLUMN auth_oauth_accounts.user_id       IS '关联本地用户 ID';
COMMENT ON COLUMN auth_oauth_accounts.provider      IS '第三方平台标识：wechat / qq';
COMMENT ON COLUMN auth_oauth_accounts.open_id       IS '第三方平台用户 OpenID';
COMMENT ON COLUMN auth_oauth_accounts.union_id      IS '第三方平台 UnionID';
COMMENT ON COLUMN auth_oauth_accounts.nickname      IS '第三方平台昵称快照';
COMMENT ON COLUMN auth_oauth_accounts.avatar        IS '第三方平台头像快照';
COMMENT ON COLUMN auth_oauth_accounts.access_token  IS '第三方平台 access_token';
COMMENT ON COLUMN auth_oauth_accounts.refresh_token IS '第三方平台 refresh_token';
COMMENT ON COLUMN auth_oauth_accounts.expires_at    IS '第三方平台 token 过期时间';

CREATE INDEX idx_auth_oauth_accounts_user ON auth_oauth_accounts (user_id);
CREATE INDEX idx_auth_oauth_accounts_union ON auth_oauth_accounts (union_id);

-- ============================================================
-- 插入默认超级管理员（系统预置唯一账号）
-- 用户名: super_admin  密码: admin123456 (bcrypt hash)
-- 实际部署时应更换密码
-- ============================================================
INSERT INTO auth_users (username, email, password_hash, nickname, status)
VALUES ('super_admin', 'super_admin@echochat.com', '$2a$10$Osjn5JVXuEHhtPwBW5Lyo.4gnyYtpFAZYrmbf5fzvN.M5DqcSggb2', '超级管理员', 1);

INSERT INTO auth_user_roles (user_id, role_id)
VALUES (1, (SELECT id FROM auth_roles WHERE code = 'super_admin'));

-- ============================================================
-- contact_friendships: 好友关系表
-- 双向存储：A→B 和 B→A 各一条记录，便于查询"我的好友列表"
-- ============================================================
CREATE TABLE contact_friendships (
    id          BIGSERIAL PRIMARY KEY,
    user_id     BIGINT   NOT NULL REFERENCES auth_users(id),
    friend_id   BIGINT   NOT NULL REFERENCES auth_users(id),
    remark      VARCHAR(50) DEFAULT '',
    group_id    BIGINT   DEFAULT NULL,
    status      SMALLINT NOT NULL DEFAULT 0,
    message     VARCHAR(200) DEFAULT '',
    created_at  TIMESTAMP(0) NOT NULL DEFAULT NOW(),
    updated_at  TIMESTAMP(0) NOT NULL DEFAULT NOW(),
    UNIQUE (user_id, friend_id)
);

COMMENT ON TABLE  contact_friendships            IS '好友关系表，双向存储（A→B和B→A各一条记录）';
COMMENT ON COLUMN contact_friendships.id         IS '记录唯一标识';
COMMENT ON COLUMN contact_friendships.user_id    IS '发起方用户 ID';
COMMENT ON COLUMN contact_friendships.friend_id  IS '好友用户 ID';
COMMENT ON COLUMN contact_friendships.remark     IS '好友备注名，仅对当前用户可见';
COMMENT ON COLUMN contact_friendships.group_id   IS '所属好友分组 ID，关联 contact_groups 表';
COMMENT ON COLUMN contact_friendships.status     IS '好友关系状态：0=待确认（已发送申请），1=已接受（互为好友），2=已拒绝，3=已拉黑';
COMMENT ON COLUMN contact_friendships.message    IS '好友申请附言';
COMMENT ON COLUMN contact_friendships.created_at IS '记录创建时间（申请发送时间）';
COMMENT ON COLUMN contact_friendships.updated_at IS '最后更新时间（状态变更时间）';

CREATE INDEX idx_friendships_user_status ON contact_friendships (user_id, status);
CREATE INDEX idx_friendships_friend_status ON contact_friendships (friend_id, status);

-- ============================================================
-- contact_groups: 好友分组表
-- 每个用户可自定义好友分组
-- ============================================================
CREATE TABLE contact_groups (
    id         BIGSERIAL PRIMARY KEY,
    user_id    BIGINT      NOT NULL REFERENCES auth_users(id),
    name       VARCHAR(50) NOT NULL,
    sort_order INT         NOT NULL DEFAULT 0,
    created_at TIMESTAMP(0) NOT NULL DEFAULT NOW()
);

COMMENT ON TABLE  contact_groups            IS '好友分组表，用户可自定义分组管理好友';
COMMENT ON COLUMN contact_groups.id         IS '分组唯一标识';
COMMENT ON COLUMN contact_groups.user_id    IS '所属用户 ID';
COMMENT ON COLUMN contact_groups.name       IS '分组名称，如"同事""家人""朋友"等';
COMMENT ON COLUMN contact_groups.sort_order IS '排序权重，数值越小越靠前';
COMMENT ON COLUMN contact_groups.created_at IS '创建时间';

CREATE INDEX idx_contact_groups_user ON contact_groups (user_id);

-- ============================================================
-- im_conversations: 会话表
-- 存储单聊（type=1）和群聊（type=2，预留）会话
-- 冗余 last_msg_* 字段以避免会话列表查询时 JOIN 消息表
-- ============================================================
CREATE TABLE im_conversations (
    id                 BIGSERIAL PRIMARY KEY,
    type               SMALLINT     NOT NULL DEFAULT 1,
    creator_id         BIGINT       NOT NULL,
    last_message_id    BIGINT       DEFAULT NULL,
    last_msg_content   TEXT         DEFAULT '',
    last_msg_time      TIMESTAMP(0) DEFAULT NULL,
    last_msg_sender_id BIGINT       DEFAULT NULL,
    created_at         TIMESTAMP(0) NOT NULL DEFAULT NOW(),
    updated_at         TIMESTAMP(0) NOT NULL DEFAULT NOW()
);

COMMENT ON TABLE  im_conversations                    IS '会话表，支持单聊（type=1）和群聊（type=2，预留）';
COMMENT ON COLUMN im_conversations.id                 IS '会话唯一标识，自增主键';
COMMENT ON COLUMN im_conversations.type               IS '会话类型：1=单聊，2=群聊（预留）';
COMMENT ON COLUMN im_conversations.creator_id         IS '会话创建者用户 ID';
COMMENT ON COLUMN im_conversations.last_message_id    IS '最后一条消息 ID，用于快速定位';
COMMENT ON COLUMN im_conversations.last_msg_content   IS '最后消息预览文本，用于会话列表展示';
COMMENT ON COLUMN im_conversations.last_msg_time      IS '最后消息时间，用于会话列表排序';
COMMENT ON COLUMN im_conversations.last_msg_sender_id IS '最后消息发送者 ID';
COMMENT ON COLUMN im_conversations.created_at         IS '会话创建时间';
COMMENT ON COLUMN im_conversations.updated_at         IS '会话信息更新时间';

CREATE INDEX idx_im_conversations_updated ON im_conversations (updated_at DESC);

-- ============================================================
-- im_conversation_members: 会话成员表
-- 每个会话的每个成员一条记录，存储个人视图（置顶/未读/软删除）
-- 单聊两条记录，群聊 N 条记录
-- ============================================================
CREATE TABLE im_conversation_members (
    id               BIGSERIAL PRIMARY KEY,
    conversation_id  BIGINT       NOT NULL REFERENCES im_conversations(id),
    user_id          BIGINT       NOT NULL,
    is_pinned        BOOLEAN      DEFAULT FALSE,
    is_deleted       BOOLEAN      DEFAULT FALSE,
    unread_count     INT          DEFAULT 0,
    last_read_msg_id     BIGINT       DEFAULT 0,
    clear_before_msg_id  BIGINT       DEFAULT 0,
    role                 SMALLINT     NOT NULL DEFAULT 0,
    nickname             VARCHAR(50)  DEFAULT '',
    is_muted             BOOLEAN      NOT NULL DEFAULT FALSE,
    is_do_not_disturb    BOOLEAN      NOT NULL DEFAULT FALSE,
    joined_at            TIMESTAMP(0) DEFAULT NULL,
    at_me_count          INT          DEFAULT 0,
    created_at           TIMESTAMP(0) NOT NULL DEFAULT NOW(),
    updated_at           TIMESTAMP(0) NOT NULL DEFAULT NOW(),
    UNIQUE (conversation_id, user_id)
);

COMMENT ON TABLE  im_conversation_members                        IS '会话成员表，存储每个成员对会话的个人视图';
COMMENT ON COLUMN im_conversation_members.id                     IS '记录唯一标识';
COMMENT ON COLUMN im_conversation_members.conversation_id        IS '所属会话 ID';
COMMENT ON COLUMN im_conversation_members.user_id                IS '成员用户 ID';
COMMENT ON COLUMN im_conversation_members.is_pinned              IS '是否置顶该会话';
COMMENT ON COLUMN im_conversation_members.is_deleted             IS '是否删除该会话（软删除，不影响对方视图）';
COMMENT ON COLUMN im_conversation_members.unread_count           IS '该成员在此会话中的未读消息数';
COMMENT ON COLUMN im_conversation_members.last_read_msg_id       IS '该成员最后已读消息 ID';
COMMENT ON COLUMN im_conversation_members.clear_before_msg_id    IS '清空聊天记录时的消息截止 ID（个人视图，不影响对方）';
COMMENT ON COLUMN im_conversation_members.role                   IS '成员角色：0=普通成员，1=管理员，2=群主';
COMMENT ON COLUMN im_conversation_members.nickname               IS '群内昵称（仅群聊有效）';
COMMENT ON COLUMN im_conversation_members.is_muted               IS '是否被禁言';
COMMENT ON COLUMN im_conversation_members.is_do_not_disturb      IS '是否消息免打扰（仍计未读但灰色显示，不推送通知）';
COMMENT ON COLUMN im_conversation_members.joined_at              IS '加入群聊时间';
COMMENT ON COLUMN im_conversation_members.at_me_count            IS '被@提醒未读计数，打开会话后清零';
COMMENT ON COLUMN im_conversation_members.created_at             IS '加入会话时间';
COMMENT ON COLUMN im_conversation_members.updated_at             IS '最后更新时间';

CREATE INDEX idx_im_conv_members_user ON im_conversation_members (user_id, is_deleted);
CREATE INDEX idx_im_conv_members_conv ON im_conversation_members (conversation_id);

-- ============================================================
-- im_messages: 消息表
-- 存储所有聊天消息，通过 conversation_id 关联会话
-- 游标分页查询核心索引：(conversation_id, created_at DESC)
-- ============================================================
CREATE TABLE im_messages (
    id              BIGSERIAL PRIMARY KEY,
    conversation_id BIGINT       NOT NULL REFERENCES im_conversations(id),
    sender_id       BIGINT       NOT NULL,
    type            SMALLINT     NOT NULL DEFAULT 1,
    content         TEXT         NOT NULL,
    extra           JSONB        DEFAULT NULL,
    status          SMALLINT     NOT NULL DEFAULT 1,
    client_msg_id   VARCHAR(64)  DEFAULT '',
    at_user_ids     BIGINT[]     DEFAULT NULL,
    created_at      TIMESTAMP(0) NOT NULL DEFAULT NOW()
);

COMMENT ON TABLE  im_messages                   IS '聊天消息表，存储所有消息内容';
COMMENT ON COLUMN im_messages.id                IS '消息唯一标识，自增主键';
COMMENT ON COLUMN im_messages.conversation_id   IS '所属会话 ID';
COMMENT ON COLUMN im_messages.sender_id         IS '发送者用户 ID';
COMMENT ON COLUMN im_messages.type              IS '消息类型：1=文本，2=图片（预留），3=语音（预留），4=视频（预留），5=文件（预留）';
COMMENT ON COLUMN im_messages.content           IS '消息内容（文本消息为纯文本，其他类型为 URL 或描述）';
COMMENT ON COLUMN im_messages.extra             IS '扩展数据（JSON 格式），预留图片尺寸、语音时长等元信息';
COMMENT ON COLUMN im_messages.status            IS '消息状态：1=正常，2=已撤回，3=已删除';
COMMENT ON COLUMN im_messages.client_msg_id     IS '客户端消息唯一 ID，用于幂等去重防止网络重试重复发送';
COMMENT ON COLUMN im_messages.at_user_ids       IS '@提醒用户 ID 列表，NULL=无@，包含 0 表示 @所有人';
COMMENT ON COLUMN im_messages.created_at        IS '消息发送时间';

CREATE INDEX idx_im_messages_conv_time ON im_messages (conversation_id, created_at DESC);
CREATE INDEX idx_im_messages_conv_id ON im_messages (conversation_id, id DESC);
CREATE INDEX idx_im_messages_content_search ON im_messages USING gin(to_tsvector('simple', content));

-- ============================================================
-- im_groups: 群聊信息表
-- 与 im_conversations (type=2) 一对一关联，存储群聊独有属性
-- ============================================================
CREATE TABLE im_groups (
    id              BIGSERIAL PRIMARY KEY,
    conversation_id BIGINT NOT NULL UNIQUE REFERENCES im_conversations(id),
    name            VARCHAR(100) NOT NULL DEFAULT '',
    avatar          VARCHAR(500) DEFAULT '',
    owner_id        BIGINT NOT NULL,
    notice          TEXT DEFAULT '',
    max_members     INT NOT NULL DEFAULT 200,
    is_searchable   BOOLEAN NOT NULL DEFAULT TRUE,
    is_all_muted    BOOLEAN NOT NULL DEFAULT FALSE,
    status          SMALLINT NOT NULL DEFAULT 1,
    created_at      TIMESTAMP(0) NOT NULL DEFAULT NOW(),
    updated_at      TIMESTAMP(0) NOT NULL DEFAULT NOW()
);

COMMENT ON TABLE  im_groups                 IS '群聊信息表';
COMMENT ON COLUMN im_groups.id              IS '群唯一标识';
COMMENT ON COLUMN im_groups.conversation_id IS '关联 im_conversations.id';
COMMENT ON COLUMN im_groups.name            IS '群名称';
COMMENT ON COLUMN im_groups.avatar          IS '群头像 URL（MinIO）';
COMMENT ON COLUMN im_groups.owner_id        IS '群主用户 ID';
COMMENT ON COLUMN im_groups.notice          IS '群公告内容';
COMMENT ON COLUMN im_groups.max_members     IS '最大成员数，默认 200';
COMMENT ON COLUMN im_groups.is_searchable   IS '是否可被搜索发现';
COMMENT ON COLUMN im_groups.is_all_muted    IS '是否全体禁言';
COMMENT ON COLUMN im_groups.status          IS '群状态：1=正常，2=已解散';

CREATE INDEX idx_im_groups_owner ON im_groups(owner_id);
CREATE INDEX idx_im_groups_name ON im_groups USING gin(to_tsvector('simple', name));

-- ============================================================
-- im_group_join_requests: 入群申请表
-- 记录用户主动申请加入群聊的审批流程
-- ============================================================
CREATE TABLE im_group_join_requests (
    id          BIGSERIAL PRIMARY KEY,
    group_id    BIGINT NOT NULL REFERENCES im_groups(id),
    user_id     BIGINT NOT NULL,
    message     TEXT DEFAULT '',
    reviewer_id BIGINT DEFAULT NULL,
    status      SMALLINT NOT NULL DEFAULT 0,
    created_at  TIMESTAMP(0) NOT NULL DEFAULT NOW(),
    updated_at  TIMESTAMP(0) NOT NULL DEFAULT NOW()
);

COMMENT ON TABLE  im_group_join_requests              IS '入群申请表';
COMMENT ON COLUMN im_group_join_requests.id            IS '申请唯一标识';
COMMENT ON COLUMN im_group_join_requests.group_id      IS '目标群 ID';
COMMENT ON COLUMN im_group_join_requests.user_id       IS '申请人用户 ID';
COMMENT ON COLUMN im_group_join_requests.message       IS '申请附言';
COMMENT ON COLUMN im_group_join_requests.reviewer_id   IS '审批人用户 ID';
COMMENT ON COLUMN im_group_join_requests.status        IS '状态：0=待审批，1=通过，2=拒绝';

CREATE INDEX idx_group_join_req_group ON im_group_join_requests(group_id, status);
CREATE INDEX idx_group_join_req_user ON im_group_join_requests(user_id);

-- ============================================================
-- im_message_reads: 群聊消息已读记录表（消息级别）
-- 复合主键 (message_id, user_id)，存储每条群消息的已读用户
-- ============================================================
CREATE TABLE im_message_reads (
    message_id BIGINT NOT NULL,
    user_id    BIGINT NOT NULL,
    read_at    TIMESTAMP(0) NOT NULL DEFAULT NOW(),
    PRIMARY KEY (message_id, user_id)
);

COMMENT ON TABLE  im_message_reads            IS '群聊消息已读记录表（消息级别）';
COMMENT ON COLUMN im_message_reads.message_id IS '消息 ID';
COMMENT ON COLUMN im_message_reads.user_id    IS '已读用户 ID';
COMMENT ON COLUMN im_message_reads.read_at    IS '已读时间';

CREATE INDEX idx_msg_reads_user ON im_message_reads(user_id, read_at);

-- ============================================================
-- notify_notifications: 通知消息表
-- 统一通知中心持久化存储，覆盖好友 / 群聊 / 会议 / 系统广播四类场景
-- 写入失败不回滚业务；WS 推送失败不回滚入库（降级策略）
-- ============================================================
CREATE TABLE notify_notifications (
    id          BIGSERIAL PRIMARY KEY,
    user_id     BIGINT       NOT NULL,
    type        VARCHAR(50)  NOT NULL,
    title       VARCHAR(100) NOT NULL DEFAULT '',
    content     VARCHAR(500) NOT NULL DEFAULT '',
    extra       JSONB        DEFAULT NULL,
    actor_id    BIGINT       DEFAULT NULL,
    target_type VARCHAR(30)  NOT NULL DEFAULT '',
    target_id   BIGINT       DEFAULT NULL,
    is_read     BOOLEAN      NOT NULL DEFAULT FALSE,
    read_at     TIMESTAMP(0) DEFAULT NULL,
    created_at  TIMESTAMP(0) NOT NULL DEFAULT NOW()
);

COMMENT ON TABLE  notify_notifications             IS '通知消息表，统一通知中心持久化载体';
COMMENT ON COLUMN notify_notifications.id          IS '通知唯一标识，自增主键';
COMMENT ON COLUMN notify_notifications.user_id     IS '接收者用户 ID（每条通知对应单个用户）';
COMMENT ON COLUMN notify_notifications.type        IS '通知类型常量：friend_request / friend_accepted / friend_rejected / group_invite / group_join_request / group_join_approved / group_join_rejected / group_kicked / group_role_changed / system_broadcast / meeting_invite / meeting_reminder';
COMMENT ON COLUMN notify_notifications.title       IS '通知标题（前端列表主文案）';
COMMENT ON COLUMN notify_notifications.content     IS '通知副文案（详细说明或申请附言）';
COMMENT ON COLUMN notify_notifications.extra       IS '扩展数据 JSON，保存类型相关的原始参数（group_id / request_id / role 等）';
COMMENT ON COLUMN notify_notifications.actor_id    IS '触发此通知的主体用户 ID（申请人 / 邀请人等），系统广播为 NULL';
COMMENT ON COLUMN notify_notifications.target_type IS '业务对象类型：user / group / meeting / system，用于点击跳转路由';
COMMENT ON COLUMN notify_notifications.target_id   IS '业务对象 ID，与 target_type 联合定位跳转目标';
COMMENT ON COLUMN notify_notifications.is_read     IS '是否已读：FALSE=未读，TRUE=已读';
COMMENT ON COLUMN notify_notifications.read_at     IS '已读时间，未读时为 NULL';
COMMENT ON COLUMN notify_notifications.created_at  IS '通知生成时间';

-- 列表查询核心索引（按用户倒序分页）
CREATE INDEX idx_notify_user_time ON notify_notifications (user_id, created_at DESC);
-- 未读数统计索引（覆盖索引）
CREATE INDEX idx_notify_user_unread ON notify_notifications (user_id, is_read) WHERE is_read = FALSE;
-- 清理任务索引（按创建时间扫描旧数据）
CREATE INDEX idx_notify_created_at ON notify_notifications (created_at);

-- ============================================================
-- Phase 2e-2 会议 MVP（设计文档 §5.1）
--   meeting_rooms         会议房间
--   meeting_participants  参与者记录
--   meeting_chats         会议内文字聊天
-- 所有时间字段沿用项目风格 TIMESTAMP(0)（而非设计草案的 TIMESTAMPTZ），与
-- auth_users / im_messages 等表保持一致；Go 侧 model 搭配 gorm:"type:timestamp(0)"。
-- ============================================================

CREATE TABLE meeting_rooms (
    id             BIGSERIAL     PRIMARY KEY,
    room_code      VARCHAR(20)   UNIQUE NOT NULL,
    title          VARCHAR(200)  NOT NULL,
    host_id        BIGINT        NOT NULL REFERENCES auth_users(id),
    type           SMALLINT      NOT NULL DEFAULT 1,
    password_hash  VARCHAR(255)  DEFAULT NULL,
    max_members    INT           NOT NULL DEFAULT 50,
    status         SMALLINT      NOT NULL DEFAULT 0,
    scheduled_at   TIMESTAMP(0)  DEFAULT NULL,
    started_at     TIMESTAMP(0)  DEFAULT NULL,
    ended_at       TIMESTAMP(0)  DEFAULT NULL,
    ended_reason   VARCHAR(20)   DEFAULT NULL,
    settings       JSONB         NOT NULL DEFAULT '{}',
    created_at     TIMESTAMP(0)  NOT NULL DEFAULT NOW(),
    updated_at     TIMESTAMP(0)  NOT NULL DEFAULT NOW()
);

COMMENT ON TABLE  meeting_rooms               IS '会议房间表';
COMMENT ON COLUMN meeting_rooms.room_code     IS '用户可见的会议号 XXX-XXX-XXX，全局唯一';
COMMENT ON COLUMN meeting_rooms.title         IS '会议标题';
COMMENT ON COLUMN meeting_rooms.host_id       IS '主持人用户 ID，引用 auth_users.id';
COMMENT ON COLUMN meeting_rooms.type          IS '会议类型：1=即时（MVP 仅此），2=预约（Phase 2e-3）';
COMMENT ON COLUMN meeting_rooms.password_hash IS '入会密码 bcrypt 哈希，NULL 表示无密码';
COMMENT ON COLUMN meeting_rooms.max_members   IS '房间最大成员数，schema 默认 50';
COMMENT ON COLUMN meeting_rooms.status        IS '0=未开始（仅预约），1=进行中，2=已结束';
COMMENT ON COLUMN meeting_rooms.scheduled_at  IS '预约开始时间，即时会议为 NULL';
COMMENT ON COLUMN meeting_rooms.started_at    IS '实际开始时间，host 首次加入时回填';
COMMENT ON COLUMN meeting_rooms.ended_at      IS '实际结束时间';
COMMENT ON COLUMN meeting_rooms.ended_reason  IS '结束原因：host_ended / empty_ttl / admin_force / system_error';
COMMENT ON COLUMN meeting_rooms.settings      IS 'JSON 配置：{mute_on_join, allow_chat, record_enabled 等}';

-- 主持人 + 状态的列表查询（如"我主持的进行中会议"）
CREATE INDEX idx_meeting_rooms_host_status ON meeting_rooms (host_id, status, created_at DESC);
-- 会议号快速查找（唯一约束已自动建索引，冗余索引已移除；入会查询走 UNIQUE）

-- ============================================================
-- meeting_participants: 参与者记录（出入场完整轨迹）
--   ON DELETE CASCADE：room 删除时自动清理参与者
--   UNIQUE(room_id, user_id)：同一用户在同一房间只有一条记录（重入仅更新 left_at=NULL）
-- ============================================================
CREATE TABLE meeting_participants (
    id          BIGSERIAL    PRIMARY KEY,
    room_id     BIGINT       NOT NULL REFERENCES meeting_rooms(id) ON DELETE CASCADE,
    user_id     BIGINT       NOT NULL REFERENCES auth_users(id),
    role        SMALLINT     NOT NULL DEFAULT 0,
    joined_at   TIMESTAMP(0) NOT NULL DEFAULT NOW(),
    left_at     TIMESTAMP(0) DEFAULT NULL,
    left_reason VARCHAR(20)  DEFAULT NULL,
    duration    INT          NOT NULL DEFAULT 0,
    UNIQUE (room_id, user_id)
);

COMMENT ON TABLE  meeting_participants             IS '会议参与者记录（一次入会一行，重入更新）';
COMMENT ON COLUMN meeting_participants.room_id     IS '所属会议房间 ID，引用 meeting_rooms.id，CASCADE 删除';
COMMENT ON COLUMN meeting_participants.user_id     IS '参与者用户 ID，引用 auth_users.id';
COMMENT ON COLUMN meeting_participants.role        IS '0=普通，1=主持人（MVP 仅此两档），2=联合主持人（第二期）';
COMMENT ON COLUMN meeting_participants.joined_at   IS '加入时间，记录创建即代表加入';
COMMENT ON COLUMN meeting_participants.left_at     IS '离开时间，NULL 表示仍在会议中';
COMMENT ON COLUMN meeting_participants.left_reason IS '离会原因：self / kicked / host_end / empty_ttl / disconnect';
COMMENT ON COLUMN meeting_participants.duration    IS '本次参会时长（秒），left_at 写入时同步计算';

-- 按房间查询成员（按加入顺序正序，便于"最早加入者接任主持人"）
CREATE INDEX idx_meeting_participants_room ON meeting_participants (room_id, joined_at ASC);
-- 按用户查询历史（"我的会议记录"）
CREATE INDEX idx_meeting_participants_user ON meeting_participants (user_id, joined_at DESC);

-- ============================================================
-- meeting_chats: 会议内文字聊天（独立于 im_messages）
--   清理策略：每日扫描 meeting_rooms.status=2 AND ended_at < NOW() - INTERVAL '24 hours'
--   批量 DELETE FROM meeting_chats WHERE room_id IN (...)
-- ============================================================
CREATE TABLE meeting_chats (
    id         BIGSERIAL    PRIMARY KEY,
    room_id    BIGINT       NOT NULL REFERENCES meeting_rooms(id) ON DELETE CASCADE,
    user_id    BIGINT       NOT NULL REFERENCES auth_users(id),
    content    TEXT         NOT NULL,
    created_at TIMESTAMP(0) NOT NULL DEFAULT NOW()
);

COMMENT ON TABLE  meeting_chats            IS '会议内文字聊天消息（会议结束 24 小时后批量清理）';
COMMENT ON COLUMN meeting_chats.room_id    IS '所属会议房间 ID，引用 meeting_rooms.id，CASCADE 删除';
COMMENT ON COLUMN meeting_chats.user_id    IS '发送者用户 ID，引用 auth_users.id';
COMMENT ON COLUMN meeting_chats.content    IS '消息内容（纯文本，MVP 不支持富媒体）';
COMMENT ON COLUMN meeting_chats.created_at IS '消息发送时间';

-- 按房间正序读取（会议室打开时按时间线加载历史聊天）
CREATE INDEX idx_meeting_chats_room_created ON meeting_chats (room_id, created_at ASC);
