-- +goose Up
-- +goose StatementBegin
-- Users
CREATE TABLE IF NOT EXISTS users(
    id bigserial PRIMARY KEY, -- 主键ID：自增
    username varchar(255) NOT NULL UNIQUE, -- 用户名：唯一，用于登录
    password VARCHAR(255) NOT NULL, -- 密码：加密存储
    roles text[] DEFAULT '{user}', -- 角色：用户角色列表，如 {user, super_admin}
    status varchar(50) DEFAULT 'active', -- 状态：active/inactive/banned
    metas jsonb DEFAULT '{}', -- 元数据：额外扩展信息
    balance bigint DEFAULT 0, -- 全局可用余额：分/最小货币单位；用户在所有已加入租户内共享该余额；默认 0
    balance_frozen bigint DEFAULT 0, -- 全局冻结余额：分/最小货币单位；用于下单冻结等；默认 0
    verified_at timestamp with time zone, -- 实名认证时间
    -- New fields
    nickname varchar(255) DEFAULT '', -- 昵称：用户显示名称
    avatar varchar(512) DEFAULT '', -- 头像：URL地址
    gender varchar(32) DEFAULT 'secret', -- 性别：male/female/secret
    bio varchar(512) DEFAULT '', -- 简介：用户个人简介
    birthday date, -- 生日：YYYY-MM-DD
    location jsonb DEFAULT '{}', -- 位置：省市区信息 {province: "...", city: "..."}
    points bigint DEFAULT 0, -- 积分：用户积分
    phone varchar(32) DEFAULT '', -- 手机号：用于登录/验证
    is_real_name_verified boolean DEFAULT FALSE, -- 是否实名认证：true/false
    created_at timestamp with time zone DEFAULT NOW(), -- 创建时间：默认 now()
    updated_at timestamp with time zone DEFAULT NOW(), -- 更新时间：默认 now()
    deleted_at timestamp with time zone -- 删除时间：软删除
);

-- Tenants
CREATE TABLE IF NOT EXISTS tenants(
    id bigserial PRIMARY KEY, -- 主键ID：自增
    user_id bigint NOT NULL, -- 创建者ID：关联 users.id
    code varchar(64) NOT NULL UNIQUE, -- 租户代码：唯一标识，用于 URL 等
    uuid uuid NOT NULL, -- UUID：全局唯一标识
    name varchar(128) NOT NULL, -- 租户名称
    status varchar(64) NOT NULL, -- 状态：pending_verify/verified/banned
    config jsonb DEFAULT '{}', -- 配置：租户配置信息
    expired_at timestamp with time zone, -- 过期时间：租户有效期
    created_at timestamp with time zone DEFAULT NOW(), -- 创建时间：默认 now()
    updated_at timestamp with time zone DEFAULT NOW() -- 更新时间：默认 now()
);

CREATE INDEX IF NOT EXISTS idx_tenants_user_id ON tenants(user_id);

-- TenantUsers
CREATE TABLE IF NOT EXISTS tenant_users(
    id bigserial PRIMARY KEY, -- 主键ID：自增
    tenant_id bigint NOT NULL, -- 租户ID：关联 tenants.id
    user_id bigint NOT NULL, -- 用户ID：关联 users.id
    role TEXT[] DEFAULT '{member}', -- 角色：member/tenant_admin
    status varchar(50) DEFAULT 'verified', -- 状态：pending_verify/verified/banned
    created_at timestamp with time zone DEFAULT NOW(), -- 创建时间：默认 now()
    updated_at timestamp with time zone DEFAULT NOW(), -- 更新时间：默认 now()
    UNIQUE (tenant_id, user_id)
);

-- Contents
CREATE TABLE IF NOT EXISTS contents(
    id bigserial PRIMARY KEY, -- 主键ID：自增；用于内容引用
    tenant_id bigint NOT NULL, -- 租户ID：多租户隔离关键字段；所有查询/写入必须限定 tenant_id
    user_id bigint NOT NULL, -- 用户ID：内容创建者/发布者；用于权限与审计（例如私有内容仅作者可见）
    title varchar(255) NOT NULL, -- 标题：用于列表展示与搜索；建议限制长度（由业务校验）
    description text NOT NULL, -- 描述：用于详情页展示；可为空字符串
    status varchar(32) DEFAULT 'draft', -- 状态：draft/reviewing/published/unpublished/blocked；published 才对外展示
    visibility varchar(32) DEFAULT 'tenant_only', -- 可见性：public/tenant_only/private；仅控制详情可见，正片资源仍需按价格/权益校验
    preview_seconds int DEFAULT 60, -- 试看秒数：默认 60；只对 preview 资源生效；必须为正整数
    preview_downloadable boolean DEFAULT FALSE, -- 试看是否允许下载：默认 false；当前策略固定为不允许下载（仅 streaming）
    published_at timestamp with time zone, -- 发布时间：首次发布时写入；用于时间窗与排序
    summary varchar(256) DEFAULT '', -- 简介：用于列表/卡片展示的短文本；建议 <= 256 字符（由业务校验）
    tags jsonb DEFAULT '[]', -- 标签：JSON 数组（字符串列表）；用于分类/检索与聚合展示
    -- New fields
    body text DEFAULT '', -- 内容主体：文章内容/详细介绍
    genre varchar(64) DEFAULT '', -- 类型/流派：如 video/audio/article 或具体的音乐流派
    views int DEFAULT 0, -- 浏览量
    likes int DEFAULT 0, -- 点赞数
    created_at timestamp with time zone DEFAULT NOW(), -- 创建时间：默认 now()；用于审计与排序
    updated_at timestamp with time zone DEFAULT NOW(), -- 更新时间：默认 now()；编辑内容时写入
    deleted_at timestamp with time zone -- 软删除时间：非空表示已删除；对外接口需过滤
);

CREATE INDEX IF NOT EXISTS idx_contents_tenant_id ON contents(tenant_id);

-- MediaAssets
CREATE TABLE IF NOT EXISTS media_assets(
    id bigserial PRIMARY KEY, -- 主键ID：自增；仅用于内部关联
    tenant_id bigint NOT NULL, -- 租户ID：多租户隔离关键字段；所有查询/写入必须限定 tenant_id
    user_id bigint NOT NULL, -- 用户ID：资源上传者；用于审计与权限控制
    type VARCHAR(32) DEFAULT 'video', -- 资源类型：video/audio/image；决定后续处理流程（转码/缩略图/封面等）
    status varchar(32) DEFAULT 'uploaded', -- 处理状态：uploaded/processing/ready/failed/deleted；ready 才可被内容引用对外提供
    provider varchar(64) NOT NULL, -- 存储提供方：例如 s3/minio/oss；便于多存储扩展
    bucket varchar(128) NOT NULL, -- 存储桶：对象所在 bucket；与 provider 组合确定存储定位
    object_key varchar(512) NOT NULL, -- 对象键：对象在 bucket 内的 key；不得暴露可长期复用的直链（通过签名URL/token下发）
    meta jsonb DEFAULT '{}', -- 元数据：JSON；包含 hash、duration、width、height、bitrate、codec 等；用于展示与计费/风控
    variant varchar(32) DEFAULT 'main', -- 产物类型：main/preview；用于强制试看资源必须绑定独立产物，避免用正片绕过
    source_asset_id bigint DEFAULT 0, -- 派生来源资源ID：preview 产物可指向对应 main 资源；用于建立 preview/main 的 1:1 追溯关系
    created_at timestamp with time zone DEFAULT NOW(), -- 创建时间：默认 now()；用于审计与排序
    updated_at timestamp with time zone DEFAULT NOW(), -- 更新时间：默认 now()；更新状态/元数据时写入
    deleted_at timestamp with time zone -- 软删除时间：非空表示已删除；对外接口需过滤
);

-- ContentAssets
CREATE TABLE IF NOT EXISTS content_assets(
    id bigserial PRIMARY KEY, -- 主键ID：自增
    tenant_id bigint NOT NULL, -- 租户ID：多租户隔离；必须与 content_id、asset_id 所属租户一致
    user_id bigint NOT NULL, -- 用户ID：操作人/绑定人；用于审计（通常为租户管理员或作者）
    content_id bigint NOT NULL, -- 内容ID：关联 contents.id；用于查询内容下资源列表
    asset_id bigint NOT NULL, -- 资源ID：关联 media_assets.id；用于查询资源归属内容
    role VARCHAR(32) DEFAULT 'main', -- 资源角色：main/cover/preview；preview 必须为独立资源以满足禁下载与防绕过
    sort int DEFAULT 0, -- 排序：同一 role 下的展示顺序，数值越小越靠前
    created_at timestamp with time zone DEFAULT NOW(), -- 创建时间：默认 now()；用于审计
    updated_at timestamp with time zone DEFAULT NOW() -- 更新时间：默认 now()；更新 sort/role 时写入
);

-- ContentPrices
CREATE TABLE IF NOT EXISTS content_prices(
    id bigserial PRIMARY KEY, -- 主键ID：自增
    tenant_id bigint NOT NULL, -- 租户ID：多租户隔离；与内容归属一致
    user_id bigint NOT NULL, -- 用户ID：设置/更新价格的操作人（通常为 tenant_admin）；用于审计
    content_id bigint NOT NULL, -- 内容ID：唯一约束 (tenant_id, content_id)；一个内容在一个租户内仅一份定价
    currency varchar(16) DEFAULT 'CNY', -- 币种：当前固定 CNY；金额单位为分
    price_amount bigint NOT NULL, -- 基础价格：分；0 表示免费（可直接访问正片资源）
    discount_type varchar(16) DEFAULT 'none', -- 折扣类型：none/percent/amount；仅影响下单时成交价，需写入订单快照
    discount_value bigint DEFAULT 0, -- 折扣值：percent=0-100（按业务校验）；amount=分；none 时忽略
    discount_start_at timestamp with time zone, -- 折扣开始时间：可为空；为空表示立即生效（由业务逻辑解释）
    discount_end_at timestamp with time zone, -- 折扣结束时间：可为空；为空表示长期有效（由业务逻辑解释）
    created_at timestamp with time zone DEFAULT NOW(), -- 创建时间：默认 now()；用于审计
    updated_at timestamp with time zone DEFAULT NOW(), -- 更新时间：默认 now()；更新价格/折扣时写入
    UNIQUE (tenant_id, content_id)
);

-- ContentAccess
CREATE TABLE IF NOT EXISTS content_access(
    id bigserial PRIMARY KEY, -- 主键ID：自增
    tenant_id bigint NOT NULL, -- 租户ID：多租户隔离；与内容、用户归属一致
    user_id bigint NOT NULL, -- 用户ID：权益所属用户；用于访问校验
    content_id bigint NOT NULL, -- 内容ID：权益对应内容；唯一约束 (tenant_id, user_id, content_id)
    order_id bigint DEFAULT 0, -- 订单ID：产生该权益的订单；可为空（例如后台补发/迁移）
    status varchar(16) DEFAULT 'active', -- 权益状态：active/revoked/expired；revoked 表示立即失效（例如退款/违规）
    revoked_at timestamp with time zone, -- 撤销时间：当 status=revoked 时写入；用于审计与追责
    created_at timestamp with time zone DEFAULT NOW(), -- 创建时间：默认 now()；用于审计
    updated_at timestamp with time zone DEFAULT NOW(), -- 更新时间：默认 now()；更新 status 时写入
    UNIQUE (tenant_id, user_id, content_id)
);

-- Orders
CREATE TABLE IF NOT EXISTS orders(
    id bigserial PRIMARY KEY, -- 主键ID：自增；用于关联订单明细、账本流水、权益等
    tenant_id bigint NOT NULL, -- 租户ID：多租户隔离关键字段；所有查询/写入必须限定 tenant_id
    user_id bigint NOT NULL, -- 用户ID：下单用户（buyer）；余额扣款与权益归属以该 user_id 为准
    type VARCHAR(32) DEFAULT 'content_purchase', -- 订单类型：content_purchase（购买内容）等；当前默认 content_purchase
    status varchar(32) DEFAULT 'created', -- 订单状态：created/paid/refunding/refunded/canceled/failed；状态变更需与账本/权益保持一致
    currency varchar(16) DEFAULT 'CNY', -- 币种：当前固定 CNY；金额单位为分
    amount_original bigint NOT NULL, -- 原价金额：分；未折扣前金额（用于展示与对账）
    amount_discount bigint NOT NULL, -- 优惠金额：分；amount_paid = amount_original - amount_discount（下单时快照）
    amount_paid bigint NOT NULL, -- 实付金额：分；从租户内余额扣款的金额（下单时快照）
    snapshot JSONB DEFAULT '{}', -- 订单快照：JSON；建议包含 content 标题/定价/折扣、请求来源等，避免改价影响历史展示
    idempotency_key varchar(128) NOT NULL, -- 幂等键：同一租户同一用户同一业务请求可用；用于防重复下单/重复扣款（建议由客户端生成）
    paid_at timestamp with time zone, -- 支付/扣款完成时间：余额支付在 debit_purchase 成功后写入
    refunded_at timestamp with time zone, -- 退款完成时间：退款落账成功后写入
    refund_forced boolean DEFAULT FALSE, -- 是否强制退款：true 表示租户管理侧绕过时间窗执行退款（需审计）
    refund_operator_user_id bigint DEFAULT 0, -- 退款操作人用户ID：租户管理员/系统；用于审计与追责
    refund_reason varchar(255) DEFAULT '', -- 退款原因：后台/用户发起退款的原因说明；用于审计
    created_at timestamp with time zone DEFAULT NOW(), -- 创建时间：默认 now()；用于审计与排序
    updated_at timestamp with time zone DEFAULT NOW() -- 更新时间：默认 now()；状态变更/退款写入时更新
);

-- OrderItems
CREATE TABLE IF NOT EXISTS order_items(
    id bigserial PRIMARY KEY, -- 主键ID：自增
    tenant_id bigint NOT NULL, -- 租户ID：多租户隔离关键字段；必须与 orders.tenant_id 一致
    user_id bigint NOT NULL, -- 用户ID：下单用户（buyer）；冗余字段用于查询加速与审计
    order_id bigint NOT NULL, -- 订单ID：关联 orders.id；用于聚合订单明细
    content_id bigint NOT NULL, -- 内容ID：关联 contents.id；用于生成/撤销 content_access
    content_user_id bigint NOT NULL, -- 内容作者用户ID：用于后续分成/对账扩展；当前可为 0 或写入内容创建者
    amount_paid bigint NOT NULL, -- 该行实付金额：分；通常等于订单 amount_paid（单内容场景）
    snapshot JSONB DEFAULT '{}', -- 内容快照：JSON；建议包含 title/price/discount 等，用于历史展示与审计
    created_at timestamp with time zone DEFAULT NOW(), -- 创建时间：默认 now()
    updated_at timestamp with time zone DEFAULT NOW() -- 更新时间：默认 now()
);

-- TenantLedgers
CREATE TABLE IF NOT EXISTS tenant_ledgers(
    id bigserial PRIMARY KEY, -- 主键ID：自增
    tenant_id bigint NOT NULL, -- 租户ID：多租户隔离关键字段；必须与 tenant_users.tenant_id 一致
    user_id bigint NOT NULL, -- 用户ID：余额账户归属用户；对应 tenant_users.user_id
    order_id bigint DEFAULT 0, -- 关联订单ID：购买/退款类流水应关联 orders.id；非订单类可为空
    type VARCHAR(32) NOT NULL, -- 流水类型：debit_purchase/credit_refund/freeze/unfreeze/adjustment；不同类型决定余额/冻结余额的变更方向
    amount bigint NOT NULL, -- 流水金额：分/最小货币单位；通常为正数，方向由 type 决定（由业务层约束）
    balance_before bigint NOT NULL, -- 变更前可用余额：用于审计与对账回放
    balance_after bigint NOT NULL, -- 变更后可用余额：用于审计与对账回放
    frozen_before bigint NOT NULL, -- 变更前冻结余额：用于审计与对账回放
    frozen_after bigint NOT NULL, -- 变更后冻结余额：用于审计与对账回放
    idempotency_key varchar(128) NOT NULL, -- 幂等键：同一租户同一用户同一业务操作固定；用于防止重复落账（建议由业务层生成）
    remark varchar(255) NOT NULL, -- 备注：业务说明/后台操作原因等；用于审计
    operator_user_id bigint DEFAULT 0, -- 操作者用户ID：谁触发该流水（admin/buyer/system）；用于审计与追责；可为空（历史数据或无法识别时）
    biz_ref_type varchar(32) DEFAULT '', -- 业务引用类型：order/refund/etc；与 biz_ref_id 组成可选的结构化幂等/追溯键
    biz_ref_id bigint DEFAULT 0, -- 业务引用ID：与 biz_ref_type 配合使用（例如 orders.id）；用于对账与审计
    created_at timestamp with time zone DEFAULT NOW(), -- 创建时间：默认 now()
    updated_at timestamp with time zone DEFAULT NOW() -- 更新时间：默认 now()
);

-- TenantInvites
CREATE TABLE IF NOT EXISTS tenant_invites(
    id bigserial PRIMARY KEY, -- 主键ID：自增
    tenant_id bigint NOT NULL, -- 租户ID：多租户隔离关键字段；所有查询/写入必须限定 tenant_id
    user_id bigint NOT NULL, -- 创建人用户ID：生成邀请码的租户管理员（审计用）
    code varchar(64) NOT NULL, -- 邀请码：用户加入租户时提交；同一租户内唯一
    status varchar(32) DEFAULT 'active', -- 邀请状态：active/disabled/expired；expired 也可由 expires_at 推导，业务侧需保持一致
    max_uses int NOT NULL, -- 最大可使用次数：0 表示不限制；>0 时 used_count 达到该值后视为失效
    used_count int DEFAULT 0, -- 已使用次数：每次成功加入时 +1；需事务保证并发下不超发
    expires_at timestamp with time zone, -- 过期时间：到期后不可再使用（UTC）；为空表示不过期
    disabled_at timestamp with time zone, -- 禁用时间：租户管理员禁用该邀请的时间（UTC）
    disabled_operator_user_id bigint DEFAULT 0, -- 禁用操作人用户ID：租户管理员（审计用）
    remark varchar(255) DEFAULT '', -- 备注：生成/禁用原因等（审计用）
    created_at timestamp with time zone DEFAULT NOW(), -- 创建时间：默认 now()
    updated_at timestamp with time zone DEFAULT NOW() -- 更新时间：默认 now()
);

-- TenantJoinRequests
CREATE TABLE IF NOT EXISTS tenant_join_requests(
    id bigserial PRIMARY KEY, -- 主键ID：自增
    tenant_id bigint NOT NULL, -- 租户ID：多租户隔离关键字段；所有查询/写入必须限定 tenant_id
    user_id bigint NOT NULL, -- 申请人用户ID：发起加入申请的用户
    status varchar(32) DEFAULT 'pending', -- 申请状态：pending/approved/rejected；状态变更需记录 decided_at 与 decided_operator_user_id
    reason varchar(255) NOT NULL, -- 申请原因：用户填写的加入说明（可选）
    decided_at timestamp with time zone, -- 处理时间：审核通过/拒绝时记录（UTC）
    decided_operator_user_id bigint DEFAULT 0, -- 处理人用户ID：租户管理员（审计用）
    decided_reason varchar(255) DEFAULT '', -- 处理说明：管理员通过/拒绝的原因（可选，审计用）
    created_at timestamp with time zone DEFAULT NOW(), -- 创建时间：默认 now()
    updated_at timestamp with time zone DEFAULT NOW() -- 更新时间：默认 now()
);

-- Comments
CREATE TABLE IF NOT EXISTS comments(
    id bigserial PRIMARY KEY, -- 主键ID：自增
    tenant_id bigint NOT NULL, -- 租户ID：关联 tenants.id
    user_id bigint NOT NULL, -- 用户ID：关联 users.id
    content_id bigint NOT NULL, -- 内容ID：关联 contents.id
    reply_to bigint DEFAULT 0, -- 回复评论ID：0表示一级评论
    content text NOT NULL, -- 评论内容
    likes int DEFAULT 0, -- 点赞数
    created_at timestamp with time zone DEFAULT NOW(), -- 创建时间：默认 now()
    updated_at timestamp with time zone DEFAULT NOW(), -- 更新时间：默认 now()
    deleted_at timestamp with time zone -- 软删除时间
);

CREATE INDEX IF NOT EXISTS idx_comments_content_id ON comments(content_id);

CREATE INDEX IF NOT EXISTS idx_comments_user_id ON comments(user_id);

-- User Content Actions (Like, Favorite)
CREATE TABLE IF NOT EXISTS user_content_actions(
    id bigserial PRIMARY KEY, -- 主键ID：自增
    user_id bigint NOT NULL, -- 用户ID
    content_id bigint NOT NULL, -- 内容ID
    type VARCHAR(32) NOT NULL, -- 类型：like, favorite
    created_at timestamp with time zone DEFAULT NOW(), -- 创建时间
    UNIQUE (user_id, content_id, type)
);

-- User Comment Actions (Like)
CREATE TABLE IF NOT EXISTS user_comment_actions(
    id bigserial PRIMARY KEY, -- 主键ID：自增
    user_id bigint NOT NULL, -- 用户ID
    comment_id bigint NOT NULL, -- 评论ID
    type VARCHAR(32) NOT NULL, -- 类型：like
    created_at timestamp with time zone DEFAULT NOW(), -- 创建时间
    UNIQUE (user_id, comment_id, type)
);

-- Payout Accounts
CREATE TABLE IF NOT EXISTS payout_accounts(
    id bigserial PRIMARY KEY, -- 主键ID：自增
    tenant_id bigint NOT NULL, -- 租户ID：关联创建者租户
    user_id bigint NOT NULL, -- 用户ID：创建者
    type VARCHAR(32) NOT NULL, -- 类型：bank, alipay
    name varchar(128) NOT NULL, -- 账户名称/开户行
    account varchar(128) NOT NULL, -- 账号
    realname varchar(128) NOT NULL, -- 真实姓名
    created_at timestamp with time zone DEFAULT NOW(), -- 创建时间
    updated_at timestamp with time zone DEFAULT NOW() -- 更新时间
);

CREATE INDEX IF NOT EXISTS idx_payout_accounts_tenant_id ON payout_accounts(tenant_id);

-- Notifications
CREATE TABLE IF NOT EXISTS notifications(
    id bigserial PRIMARY KEY, -- 主键ID：自增
    user_id bigint NOT NULL, -- 接收用户ID
    tenant_id bigint DEFAULT 0, -- 来源租户ID：可选
    type VARCHAR(32) NOT NULL, -- 类型：system, order, audit, interaction
    title varchar(255) NOT NULL, -- 标题
    content text NOT NULL, -- 内容
    is_read boolean DEFAULT FALSE, -- 是否已读
    created_at timestamp with time zone DEFAULT NOW() -- 创建时间
);

CREATE INDEX IF NOT EXISTS idx_notifications_user_id ON notifications(user_id);

-- +goose StatementEnd
-- +goose Down
-- +goose StatementBegin
DROP TABLE IF EXISTS notifications;

DROP TABLE IF EXISTS payout_accounts;

DROP TABLE IF EXISTS user_comment_actions;

DROP TABLE IF EXISTS user_content_actions;

DROP TABLE IF EXISTS comments;

DROP TABLE IF EXISTS tenant_join_requests;

DROP TABLE IF EXISTS tenant_invites;

DROP TABLE IF EXISTS tenant_ledgers;

DROP TABLE IF EXISTS order_items;

DROP TABLE IF EXISTS orders;

DROP TABLE IF EXISTS content_access;

DROP TABLE IF EXISTS content_prices;

DROP TABLE IF EXISTS content_assets;

DROP TABLE IF EXISTS media_assets;

DROP TABLE IF EXISTS contents;

DROP TABLE IF EXISTS tenant_users;

DROP TABLE IF EXISTS tenants;

DROP TABLE IF EXISTS users;

-- +goose StatementEnd
