-- BlindMaster schema. Idempotent: CREATE … IF NOT EXISTS so it works on a
-- fresh DB and replays cleanly against an existing one.

-- ── Core auth ───────────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS users (
  id                    SERIAL       PRIMARY KEY,
  name                  TEXT,
  email                 TEXT         NOT NULL UNIQUE,
  password_hash_string  TEXT         NOT NULL,
  verification_token    TEXT,
  is_verified           BOOLEAN      NOT NULL DEFAULT FALSE,
  timezone              TEXT         DEFAULT 'America/Chicago',
  apns_token            TEXT,
  fcm_token             TEXT,                  -- legacy (FCM era), kept harmless
  created_at            TIMESTAMPTZ  DEFAULT NOW()
);

-- One active session token per user. Code does delete-then-insert on login,
-- so PK on user_id enforces it.
CREATE TABLE IF NOT EXISTS user_tokens (
  user_id    INTEGER  PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
  token      TEXT     NOT NULL UNIQUE,
  connected  BOOLEAN  NOT NULL DEFAULT FALSE,
  socket     TEXT
);

CREATE TABLE IF NOT EXISTS password_reset_tokens (
  email       TEXT         PRIMARY KEY,
  token       TEXT         NOT NULL,
  expires_at  TIMESTAMPTZ  NOT NULL,
  created_at  TIMESTAMPTZ  DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS user_pending_emails (
  user_id        INTEGER      PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
  pending_email  TEXT         NOT NULL,
  token          TEXT         NOT NULL,
  expires_at     TIMESTAMPTZ  NOT NULL
);

-- ── Hardware: hubs (devices) and their controlled blinds (peripherals) ──────
CREATE TABLE IF NOT EXISTS devices (
  id           SERIAL    PRIMARY KEY,
  user_id      INTEGER   NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  device_name  TEXT      NOT NULL,
  max_ports    INTEGER   NOT NULL DEFAULT 4,
  battery_soc  SMALLINT,
  timezone     TEXT,
  UNIQUE (user_id, device_name)
);

-- token UNIQUE so socket-auth can `select device_id … where token=$1` quickly.
CREATE TABLE IF NOT EXISTS device_tokens (
  device_id  INTEGER  NOT NULL REFERENCES devices(id) ON DELETE CASCADE,
  token      TEXT     NOT NULL UNIQUE,
  connected  BOOLEAN  NOT NULL DEFAULT FALSE,
  socket     TEXT
);
CREATE INDEX IF NOT EXISTS device_tokens_device_id_idx ON device_tokens(device_id);

CREATE TABLE IF NOT EXISTS peripherals (
  id                 SERIAL       PRIMARY KEY,
  device_id          INTEGER      NOT NULL REFERENCES devices(id) ON DELETE CASCADE,
  user_id            INTEGER      NOT NULL REFERENCES users(id)   ON DELETE CASCADE,
  peripheral_number  INTEGER      NOT NULL,
  peripheral_name    TEXT         NOT NULL,
  last_pos           INTEGER,
  last_set           TIMESTAMPTZ,
  calibrated         BOOLEAN      DEFAULT FALSE,
  await_calib        BOOLEAN      DEFAULT FALSE,
  UNIQUE (device_id, peripheral_number)
);
CREATE INDEX IF NOT EXISTS peripherals_user_id_idx ON peripherals(user_id);

-- ── Multi-blind groups (e.g. "all kitchen blinds") ──────────────────────────
CREATE TABLE IF NOT EXISTS groups (
  id          SERIAL       PRIMARY KEY,
  user_id     INTEGER      NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  name        TEXT         NOT NULL,
  timezone    TEXT,
  created_at  TIMESTAMPTZ  DEFAULT NOW(),
  UNIQUE (user_id, name)
);

CREATE TABLE IF NOT EXISTS group_peripherals (
  group_id       INTEGER  NOT NULL REFERENCES groups(id)      ON DELETE CASCADE,
  peripheral_id  INTEGER  NOT NULL REFERENCES peripherals(id) ON DELETE CASCADE,
  PRIMARY KEY (group_id, peripheral_id)
);

-- ── Idempotent column additions for older DBs ───────────────────────────────
-- These mirror the runtime-bootstrap ALTERs the index.js used to do on every
-- startup. Safe on fresh DBs because the columns are already in CREATE TABLE.
ALTER TABLE users   ADD COLUMN IF NOT EXISTS apns_token  TEXT;
ALTER TABLE users   ADD COLUMN IF NOT EXISTS timezone    TEXT DEFAULT 'America/Chicago';
ALTER TABLE devices ADD COLUMN IF NOT EXISTS battery_soc SMALLINT;
ALTER TABLE devices ADD COLUMN IF NOT EXISTS timezone    TEXT;
ALTER TABLE groups  ADD COLUMN IF NOT EXISTS timezone    TEXT;
