-- M7 #352 slice 1: playlists CRUD foundation.
-- See docs/superpowers/specs/2026-05-03-m7-playlists-crud-design.md.

CREATE TABLE playlists (
    id           uuid        PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id      uuid        NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    name         text        NOT NULL,
    description  text        NOT NULL DEFAULT '',
    is_public    boolean     NOT NULL DEFAULT false,
    cover_path   text,
    track_count  integer     NOT NULL DEFAULT 0,
    duration_sec integer     NOT NULL DEFAULT 0,
    created_at   timestamptz NOT NULL DEFAULT now(),
    updated_at   timestamptz NOT NULL DEFAULT now()
);

CREATE INDEX playlists_user_idx   ON playlists (user_id, updated_at DESC);
CREATE INDEX playlists_public_idx ON playlists (is_public, updated_at DESC) WHERE is_public;

-- track_id is nullable + ON DELETE SET NULL so deleting a track from
-- the library doesn't silently drop entries from operators' playlists.
-- Denormalized title/artist/album/duration carry a snapshot so the row
-- is still legible after the upstream track row is gone.
CREATE TABLE playlist_tracks (
    playlist_id  uuid        NOT NULL REFERENCES playlists(id) ON DELETE CASCADE,
    position     integer     NOT NULL,
    track_id     uuid        REFERENCES tracks(id) ON DELETE SET NULL,
    title        text        NOT NULL,
    artist_name  text        NOT NULL,
    album_title  text        NOT NULL,
    duration_sec integer     NOT NULL,
    added_at     timestamptz NOT NULL DEFAULT now(),
    PRIMARY KEY (playlist_id, position)
);

-- Partial index supports the FK lookup that fires when a track is
-- deleted (ON DELETE SET NULL) — without it, deleting a track triggers
-- a full scan of playlist_tracks.
CREATE INDEX playlist_tracks_track_idx ON playlist_tracks (track_id) WHERE track_id IS NOT NULL;
