-- 005_races.sql — race plan, finished race archive, queue.
--
-- Storage split:
--   * Active races (lobby/countdown/racing) live in-memory in lobby.Service.
--   * Finished races are snapshotted into finished_races on SetRaceStatus(finished).
--   * Race plans describe recurring / one-off scheduled races; the scheduler
--     materializes them into lobby.RaceMeta as their start_at_ms approaches.
--   * Queue entries are per-driver per-race_id subscriptions to the next
--     upcoming races. Driver is auto-attached when a slot opens.
--
-- Keyset pagination:
--   * finished_races ordered by (finished_ms DESC, id DESC). Cursor encodes
--     (finished_ms, id); lookup uses (finished_ms, id) < (cursor_ms, cursor_id).
--   * race_plans ordered by (start_at_ms ASC, id ASC). Cursor is
--     (start_at_ms, id) with strict-less comparison.

CREATE TABLE IF NOT EXISTS finished_races (
    id              TEXT PRIMARY KEY,
    name            TEXT NOT NULL,
    host_id         TEXT NOT NULL,
    host_name       TEXT NOT NULL DEFAULT '',
    track_id        TEXT NOT NULL DEFAULT '',
    max_cars        INT  NOT NULL,
    laps            INT  NOT NULL,
    time_limit_s    INT  NOT NULL,
    driver_ids      TEXT[] NOT NULL DEFAULT '{}',
    status          TEXT NOT NULL DEFAULT 'finished'
                    CHECK (status IN ('finished', 'cancelled')),
    created_ms      BIGINT NOT NULL,
    started_ms      BIGINT NOT NULL DEFAULT 0,
    finished_ms     BIGINT NOT NULL,
    duration_ms     BIGINT NOT NULL DEFAULT 0,
    total_laps      INT  NOT NULL DEFAULT 0,
    total_drivers   INT  NOT NULL DEFAULT 0,
    winner_driver_id TEXT NOT NULL DEFAULT '',
    winner_name     TEXT NOT NULL DEFAULT '',
    best_lap_ms     BIGINT NOT NULL DEFAULT 0
);

CREATE INDEX IF NOT EXISTS finished_races_finished_ms_id_idx
    ON finished_races (finished_ms DESC, id DESC);
CREATE INDEX IF NOT EXISTS finished_races_host_idx
    ON finished_races (host_id);
CREATE INDEX IF NOT EXISTS finished_races_track_idx
    ON finished_races (track_id);
CREATE INDEX IF NOT EXISTS finished_races_status_idx
    ON finished_races (status);

-- ---------------------------------------------------------------------------
-- Race plans
-- ---------------------------------------------------------------------------

CREATE TABLE IF NOT EXISTS race_plans (
    id            TEXT PRIMARY KEY,
    name          TEXT NOT NULL,
    track_id      TEXT NOT NULL DEFAULT 'default',
    max_cars      INT  NOT NULL,
    laps          INT  NOT NULL DEFAULT 0,
    time_limit_s  INT  NOT NULL DEFAULT 0,
    host_id       TEXT NOT NULL,
    host_name     TEXT NOT NULL DEFAULT '',
    start_at_ms   BIGINT NOT NULL,
    interval_s    INT  NOT NULL DEFAULT 0,  -- 0 = single-shot
    count         INT  NOT NULL DEFAULT 0,  -- 0 = repeat forever
    enabled       BOOLEAN NOT NULL DEFAULT TRUE,
    created_ms    BIGINT NOT NULL,
    updated_ms    BIGINT NOT NULL,
    next_fire_ms  BIGINT NOT NULL,          -- last materialised fire time
    fires_done    INT  NOT NULL DEFAULT 0
);

CREATE INDEX IF NOT EXISTS race_plans_start_idx
    ON race_plans (start_at_ms ASC, id ASC);
CREATE INDEX IF NOT EXISTS race_plans_enabled_idx
    ON race_plans (enabled, next_fire_ms);

-- ---------------------------------------------------------------------------
-- Queue
-- ---------------------------------------------------------------------------

CREATE TABLE IF NOT EXISTS race_queue (
    driver_id  TEXT NOT NULL,
    race_id    TEXT NOT NULL,
    plan_id    TEXT NOT NULL DEFAULT '',
    enqueued_ms BIGINT NOT NULL,
    PRIMARY KEY (driver_id, race_id)
);

CREATE INDEX IF NOT EXISTS race_queue_race_idx ON race_queue (race_id);
CREATE INDEX IF NOT EXISTS race_queue_driver_idx ON race_queue (driver_id, enqueued_ms);
