-- =============================================================================
-- 镭射卡重构 v3 — 业务表迁移（Phase 1）+ COMMENT + 种子数据
-- 合并版，避免 \ir 路径和 PowerShell 编码问题
-- =============================================================================

BEGIN;

-- -----------------------------------------------------------------------------
-- 1. laser_card_templates
-- -----------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS public.laser_card_templates (
    id                  BIGSERIAL PRIMARY KEY,
    template_code       VARCHAR(64)  NOT NULL,
    name                VARCHAR(100) NOT NULL,
    description         TEXT,
    status              VARCHAR(20)  NOT NULL DEFAULT 'published',
    version             INT          NOT NULL DEFAULT 1,
    thumbnail_oss_key   VARCHAR(255),
    backdrop_options    JSONB        NOT NULL DEFAULT '[]'::jsonb,
    render_config       JSONB        NOT NULL DEFAULT '{}'::jsonb,
    engine_min_version  VARCHAR(32)  NOT NULL DEFAULT 'compositor-1.0.0',
    sort_order          INT          NOT NULL DEFAULT 0,
    star_id             BIGINT       NOT NULL DEFAULT 0,
    created_by          BIGINT       NOT NULL DEFAULT 0,
    created_at          BIGINT       NOT NULL,
    updated_at          BIGINT       NOT NULL,
    deleted_at          BIGINT
);

CREATE UNIQUE INDEX IF NOT EXISTS uk_lct_code_version
    ON public.laser_card_templates (template_code, version)
    WHERE deleted_at IS NULL;

CREATE INDEX IF NOT EXISTS idx_lct_status_star
    ON public.laser_card_templates (status, star_id)
    WHERE deleted_at IS NULL;

-- -----------------------------------------------------------------------------
-- 2. laser_card_instances
-- -----------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS public.laser_card_instances (
    id                      BIGSERIAL PRIMARY KEY,
    instance_no             VARCHAR(32)  NOT NULL,
    instance_ulid           VARCHAR(40)  NOT NULL,
    template_id             BIGINT       NOT NULL,
    template_code           VARCHAR(64)  NOT NULL,
    template_version        INT          NOT NULL,
    owner_user_id           BIGINT       NOT NULL,
    star_id                 BIGINT       NOT NULL,
    status                  VARCHAR(20)  NOT NULL DEFAULT 'rendered',
    client_request_id       VARCHAR(64),
    render_config           JSONB,
    materials_snapshot      JSONB        NOT NULL DEFAULT '[]'::jsonb,
    composite_oss_key       VARCHAR(255),
    composite_material_id   BIGINT,
    asset_id                BIGINT,
    mint_order_id           VARCHAR(100),
    idempotency_key         VARCHAR(64),
    version                 INT          NOT NULL DEFAULT 1,
    created_at              BIGINT       NOT NULL,
    updated_at              BIGINT       NOT NULL,
    deleted_at              BIGINT,

    CONSTRAINT fk_lci_template
        FOREIGN KEY (template_id) REFERENCES public.laser_card_templates (id),
    CONSTRAINT fk_lci_asset
        FOREIGN KEY (asset_id) REFERENCES public.assets (id) ON DELETE SET NULL,
    CONSTRAINT fk_lci_mint_order
        FOREIGN KEY (mint_order_id) REFERENCES public.mint_orders (order_id) ON DELETE SET NULL,
    CONSTRAINT fk_lci_composite_material
        FOREIGN KEY (composite_material_id) REFERENCES public.materials (id) ON DELETE SET NULL,
    CONSTRAINT chk_lci_status
        CHECK (status IN ('rendered', 'minting', 'minted'))
);

CREATE UNIQUE INDEX IF NOT EXISTS uk_lci_instance_no
    ON public.laser_card_instances (instance_no);

CREATE UNIQUE INDEX IF NOT EXISTS uk_lci_instance_ulid
    ON public.laser_card_instances (instance_ulid);

CREATE UNIQUE INDEX IF NOT EXISTS uk_lci_user_client_req
    ON public.laser_card_instances (owner_user_id, client_request_id)
    WHERE deleted_at IS NULL AND client_request_id IS NOT NULL;

CREATE INDEX IF NOT EXISTS idx_lci_owner_status
    ON public.laser_card_instances (owner_user_id, status)
    WHERE deleted_at IS NULL;

CREATE INDEX IF NOT EXISTS idx_lci_asset
    ON public.laser_card_instances (asset_id)
    WHERE asset_id IS NOT NULL AND deleted_at IS NULL;

CREATE INDEX IF NOT EXISTS idx_lci_star_created
    ON public.laser_card_instances (star_id, created_at DESC)
    WHERE deleted_at IS NULL;

-- -----------------------------------------------------------------------------
-- 3. laser_card_operation_logs
-- -----------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS public.laser_card_operation_logs (
    id                  BIGSERIAL PRIMARY KEY,
    instance_id         BIGINT       NOT NULL,
    instance_no         VARCHAR(32)  NOT NULL,
    operator_user_id    BIGINT       NOT NULL,
    action              VARCHAR(50)  NOT NULL,
    status_before       VARCHAR(20),
    status_after        VARCHAR(20),
    request_id          VARCHAR(64),
    payload_json        JSONB,
    result_json         JSONB,
    ip_address          VARCHAR(45),
    user_agent          VARCHAR(255),
    latency_ms          INT,
    err_code            VARCHAR(32),
    created_at          BIGINT       NOT NULL,

    CONSTRAINT fk_lclog_instance
        FOREIGN KEY (instance_id) REFERENCES public.laser_card_instances (id) ON DELETE CASCADE
);

CREATE INDEX IF NOT EXISTS idx_lclog_instance_time
    ON public.laser_card_operation_logs (instance_id, created_at DESC);

CREATE INDEX IF NOT EXISTS idx_lclog_operator_time
    ON public.laser_card_operation_logs (operator_user_id, created_at DESC);

CREATE INDEX IF NOT EXISTS idx_lclog_action_time
    ON public.laser_card_operation_logs (action, created_at DESC);

-- =============================================================================
-- 4. 表 / 字段 / 索引 / 约束备注
-- =============================================================================

COMMENT ON TABLE public.laser_card_templates IS
    '镭射卡预设模板表。内置 5 套预设（dream/classic/holoFull/ice/sunset），与前端 laserPresets.js 对齐；本期只读种子，无管理端 CRUD。';

COMMENT ON COLUMN public.laser_card_templates.id IS '主键，自增';
COMMENT ON COLUMN public.laser_card_templates.template_code IS '业务编码，与五图 presetId 一致：dream | classic | holoFull | ice | sunset';
COMMENT ON COLUMN public.laser_card_templates.name IS 'C 端展示名称，如「梦幻」「全息」';
COMMENT ON COLUMN public.laser_card_templates.description IS '模板描述，可选';
COMMENT ON COLUMN public.laser_card_templates.status IS '发布状态：published（可用）| archived（下线）';
COMMENT ON COLUMN public.laser_card_templates.version IS '模板版本号；与 template_code 联合唯一（uk_lct_code_version）';
COMMENT ON COLUMN public.laser_card_templates.thumbnail_oss_key IS '列表缩略图 OSS 对象键，可选';
COMMENT ON COLUMN public.laser_card_templates.backdrop_options IS '底纹选项 JSON 数组，元素含 id/label/oss_key';
COMMENT ON COLUMN public.laser_card_templates.render_config IS '默认渲染参数 JSON：style/angle/beam/backdrop/laserStrength 等';
COMMENT ON COLUMN public.laser_card_templates.engine_min_version IS '最低客户端合成器版本，默认 compositor-1.0.0';
COMMENT ON COLUMN public.laser_card_templates.sort_order IS '模板列表排序，越小越靠前';
COMMENT ON COLUMN public.laser_card_templates.star_id IS '所属明星/星球 ID；0 表示全站通用模板';
COMMENT ON COLUMN public.laser_card_templates.created_by IS '创建人用户 ID；种子数据填 0';
COMMENT ON COLUMN public.laser_card_templates.created_at IS '创建时间，毫秒时间戳';
COMMENT ON COLUMN public.laser_card_templates.updated_at IS '更新时间，毫秒时间戳';
COMMENT ON COLUMN public.laser_card_templates.deleted_at IS '软删除时间，毫秒时间戳；NULL 表示未删除';

COMMENT ON INDEX public.uk_lct_code_version IS '同 template_code + version 在未删除行内唯一';
COMMENT ON INDEX public.idx_lct_status_star IS '按发布状态与 star_id 筛选模板列表';

COMMENT ON TABLE public.laser_card_instances IS
    '镭射卡业务实例表。一次「上传→五图选卡→铸造」对应一行；铸造前素材存 materials_snapshot，成功后回填 asset_id、mint_order_id。品类/工艺不写本表，见 assets.tags（cast:star_card + craft:laser）。';

COMMENT ON COLUMN public.laser_card_instances.id IS '主键，自增；对内使用';
COMMENT ON COLUMN public.laser_card_instances.instance_no IS '业务单号，UK；格式 LC + yyyyMMddHHmmss + 6 位随机';
COMMENT ON COLUMN public.laser_card_instances.instance_ulid IS '对外实例 ID，UK；如 lc_inst_01HXYZ...，API 路径参数';
COMMENT ON COLUMN public.laser_card_instances.template_id IS 'FK -> laser_card_templates.id，用户选中的预设';
COMMENT ON COLUMN public.laser_card_instances.template_code IS '模板编码冗余，避免列表 JOIN templates';
COMMENT ON COLUMN public.laser_card_instances.template_version IS '创建实例时锁定的模板版本快照';
COMMENT ON COLUMN public.laser_card_instances.owner_user_id IS '持有者用户 ID；鉴权须等于 JWT user_id';
COMMENT ON COLUMN public.laser_card_instances.star_id IS '多星隔离：所属明星/星球 ID';
COMMENT ON COLUMN public.laser_card_instances.status IS '状态机：rendered（已选卡未铸造）| minting（铸造中）| minted（已完成）';
COMMENT ON COLUMN public.laser_card_instances.client_request_id IS '客户端幂等 UUID；与 owner_user_id 联合唯一';
COMMENT ON COLUMN public.laser_card_instances.render_config IS '用户最终渲染参数 JSON 快照，可选';
COMMENT ON COLUMN public.laser_card_instances.materials_snapshot IS
    '铸造前素材 OSS 清单 JSON 数组。每项字段：role(source|cutout|backdrop|composite)、oss_key、hash、width、height、mime_type、file_size、preset_id';
COMMENT ON COLUMN public.laser_card_instances.composite_oss_key IS '用户选中的合成图 OSS key';
COMMENT ON COLUMN public.laser_card_instances.composite_material_id IS '铸造成功后回填 materials.id';
COMMENT ON COLUMN public.laser_card_instances.asset_id IS 'FK -> assets.id；铸造成功后回填，铸造前为 NULL';
COMMENT ON COLUMN public.laser_card_instances.mint_order_id IS 'FK -> mint_orders.order_id；发起铸造时关联';
COMMENT ON COLUMN public.laser_card_instances.idempotency_key IS '最后一次写操作的幂等键，可选';
COMMENT ON COLUMN public.laser_card_instances.version IS '乐观锁版本号，每次更新实例 +1';
COMMENT ON COLUMN public.laser_card_instances.created_at IS '创建时间，毫秒时间戳';
COMMENT ON COLUMN public.laser_card_instances.updated_at IS '更新时间，毫秒时间戳';
COMMENT ON COLUMN public.laser_card_instances.deleted_at IS '软删除时间，毫秒时间戳；NULL 表示未删除';

COMMENT ON INDEX public.uk_lci_instance_no IS '业务单号唯一';
COMMENT ON INDEX public.uk_lci_instance_ulid IS '对外实例 ID 唯一';
COMMENT ON INDEX public.uk_lci_user_client_req IS '同一用户下 client_request_id 幂等';
COMMENT ON INDEX public.idx_lci_owner_status IS '按用户与状态查实例列表';
COMMENT ON INDEX public.idx_lci_asset IS '按已铸造资产反查实例';
COMMENT ON INDEX public.idx_lci_star_created IS '按星球与时间倒序列表';

COMMENT ON TABLE public.laser_card_operation_logs IS
    '镭射卡操作审计流水表。只追加不更新；记录 create_instance / mint_start / mint_success / mint_fail 等。';

COMMENT ON COLUMN public.laser_card_operation_logs.id IS '主键，自增';
COMMENT ON COLUMN public.laser_card_operation_logs.instance_id IS 'FK -> laser_card_instances.id；实例删除时级联删除日志';
COMMENT ON COLUMN public.laser_card_operation_logs.instance_no IS '实例业务单号冗余，便于按单号检索';
COMMENT ON COLUMN public.laser_card_operation_logs.operator_user_id IS '操作人用户 ID';
COMMENT ON COLUMN public.laser_card_operation_logs.action IS '动作：create_instance | generate_variants | mint_start | mint_success | mint_fail';
COMMENT ON COLUMN public.laser_card_operation_logs.status_before IS '变更前实例 status，可选';
COMMENT ON COLUMN public.laser_card_operation_logs.status_after IS '变更后实例 status，可选';
COMMENT ON COLUMN public.laser_card_operation_logs.request_id IS '请求追踪 ID，可选';
COMMENT ON COLUMN public.laser_card_operation_logs.payload_json IS '请求摘要 JSON，禁止存图片二进制';
COMMENT ON COLUMN public.laser_card_operation_logs.result_json IS '响应摘要 JSON，可选';
COMMENT ON COLUMN public.laser_card_operation_logs.ip_address IS '客户端 IP，IPv4/IPv6';
COMMENT ON COLUMN public.laser_card_operation_logs.user_agent IS '客户端 User-Agent';
COMMENT ON COLUMN public.laser_card_operation_logs.latency_ms IS '接口耗时（毫秒），可选';
COMMENT ON COLUMN public.laser_card_operation_logs.err_code IS '失败时的业务错误码，可选';
COMMENT ON COLUMN public.laser_card_operation_logs.created_at IS '日志创建时间，毫秒时间戳';

COMMENT ON INDEX public.idx_lclog_instance_time IS '按实例查操作历史（时间倒序）';
COMMENT ON INDEX public.idx_lclog_operator_time IS '按操作人查历史';
COMMENT ON INDEX public.idx_lclog_action_time IS '按动作类型统计与排查';

COMMENT ON CONSTRAINT fk_lci_template ON public.laser_card_instances IS
    '关联所选镭射预设模板';
COMMENT ON CONSTRAINT fk_lci_asset ON public.laser_card_instances IS
    '铸造成功后的藏品 assets.id；删除资产时置 NULL';
COMMENT ON CONSTRAINT fk_lci_mint_order ON public.laser_card_instances IS
    '关联铸造订单 mint_orders.order_id';
COMMENT ON CONSTRAINT fk_lci_composite_material ON public.laser_card_instances IS
    '选中合成图在 materials 表中的主键';
COMMENT ON CONSTRAINT chk_lci_status ON public.laser_card_instances IS
    '实例状态枚举：rendered | minting | minted';

COMMENT ON CONSTRAINT fk_lclog_instance ON public.laser_card_operation_logs IS
    '关联镭射实例；实例删除时级联删除审计日志';

-- =============================================================================
-- 5. 种子数据：5 套预设
-- =============================================================================
INSERT INTO public.laser_card_templates (
    template_code,
    name,
    status,
    version,
    backdrop_options,
    render_config,
    engine_min_version,
    sort_order,
    star_id,
    created_by,
    created_at,
    updated_at
)
SELECT
    v.template_code,
    v.name,
    'published',
    1,
    v.backdrop_options::jsonb,
    v.render_config::jsonb,
    'compositor-1.0.0',
    v.sort_order,
    0,
    0,
    (EXTRACT(EPOCH FROM clock_timestamp()) * 1000)::bigint,
    (EXTRACT(EPOCH FROM clock_timestamp()) * 1000)::bigint
FROM (
    VALUES
        ('dream', '梦幻', 0, '[{"id":"liquidBlue","label":"液态蓝","oss_key":"static/laser-bg/laser-bg-1.png"}]', '{"style":"dream","angle":36,"beam":"prism","backdrop":"liquidBlue","laserStrength":78,"diffractionDensity":68,"marbleFlow":52,"beamIntensity":92,"grainDensity":82}'),
        ('classic', '经典', 1, '[{"id":"liquidLavender","label":"液态紫","oss_key":"static/laser-bg/laser-bg-2.png"}]', '{"style":"classic","angle":24,"beam":"aurora","backdrop":"liquidLavender","laserStrength":85,"diffractionDensity":74,"marbleFlow":38,"beamIntensity":96,"grainDensity":76}'),
        ('holoFull', '全息', 2, '[{"id":"liquidPearl","label":"液态珍珠","oss_key":"static/laser-bg/laser-bg-3.png"}]', '{"style":"holoFull","angle":58,"beam":"neon","backdrop":"liquidPearl","laserStrength":90,"diffractionDensity":80,"marbleFlow":58,"beamIntensity":100,"grainDensity":88}'),
        ('ice', '冰蓝', 3, '[{"id":"liquidBlue","label":"液态蓝","oss_key":"static/laser-bg/laser-bg-1.png"}]', '{"style":"ice","angle":46,"beam":"white","backdrop":"liquidBlue","laserStrength":72,"diffractionDensity":60,"marbleFlow":44,"beamIntensity":88,"grainDensity":74}'),
        ('sunset', '晚霞', 4, '[{"id":"liquidLavender","label":"液态紫","oss_key":"static/laser-bg/laser-bg-2.png"}]', '{"style":"sunset","angle":30,"beam":"sunset","backdrop":"liquidLavender","laserStrength":82,"diffractionDensity":66,"marbleFlow":50,"beamIntensity":94,"grainDensity":84}')
) AS v (template_code, name, sort_order, backdrop_options, render_config)
WHERE NOT EXISTS (
    SELECT 1
    FROM public.laser_card_templates t
    WHERE t.template_code = v.template_code
      AND t.version = 1
      AND t.deleted_at IS NULL
);

COMMIT;
