-- ClickTrack PostgreSQL schema
-- Run via: psql $DATABASE_URL -f lib/db/schema.sql
-- Or applied automatically by docker/init.sql on first container start.

-- Enable UUID generation
CREATE EXTENSION IF NOT EXISTS "pgcrypto";

-- ─── songs ────────────────────────────────────────────────────────────────────
-- Canonical song records, populated from MusicBrainz lookups and/or
-- community contributions. mbid is the MusicBrainz Recording UUID.

CREATE TABLE IF NOT EXISTS songs (
  mbid               UUID          PRIMARY KEY,
  title              TEXT          NOT NULL,
  artist             TEXT          NOT NULL,
  -- Duration in seconds as reported by MusicBrainz
  duration_seconds   NUMERIC(8, 3),
  -- AcousticBrainz / AcousticBrainz-derived BPM estimate (nullable)
  acousticbrainz_bpm NUMERIC(6, 2),
  -- AcousticBrainz time signature numerator (e.g. 4 for 4/4)
  acousticbrainz_time_sig_num INTEGER,
  -- How this record was created: 'musicbrainz' | 'manual' | 'registry'
  source             TEXT          NOT NULL DEFAULT 'musicbrainz',
  created_at         TIMESTAMPTZ   NOT NULL DEFAULT NOW(),
  updated_at         TIMESTAMPTZ   NOT NULL DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS songs_title_artist_idx
  ON songs USING gin(to_tsvector('english', title || ' ' || artist));

-- ─── tempo_maps ───────────────────────────────────────────────────────────────
-- Community-contributed CTP documents for a given song.
-- Multiple maps per song are allowed; clients pick the highest-voted verified one.

CREATE TABLE IF NOT EXISTS tempo_maps (
  id             UUID          PRIMARY KEY DEFAULT gen_random_uuid(),
  song_mbid      UUID          NOT NULL REFERENCES songs(mbid) ON DELETE CASCADE,
  -- Full CTP document stored as JSONB for flexible querying
  ctp_data       JSONB         NOT NULL,
  contributed_by TEXT          NOT NULL,
  verified       BOOLEAN       NOT NULL DEFAULT FALSE,
  upvotes        INTEGER       NOT NULL DEFAULT 0,
  created_at     TIMESTAMPTZ   NOT NULL DEFAULT NOW(),
  updated_at     TIMESTAMPTZ   NOT NULL DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS tempo_maps_song_mbid_idx ON tempo_maps (song_mbid);
CREATE INDEX IF NOT EXISTS tempo_maps_verified_upvotes_idx
  ON tempo_maps (verified DESC, upvotes DESC);

-- Ensure ctp_data contains at least a version field
ALTER TABLE tempo_maps
  ADD CONSTRAINT ctp_data_has_version
  CHECK (ctp_data ? 'version');

-- ─── registry_sync_log ────────────────────────────────────────────────────────
-- Audit log for Git registry sync operations.

CREATE TABLE IF NOT EXISTS registry_sync_log (
  id              UUID          PRIMARY KEY DEFAULT gen_random_uuid(),
  synced_at       TIMESTAMPTZ   NOT NULL DEFAULT NOW(),
  records_added   INTEGER       NOT NULL DEFAULT 0,
  records_updated INTEGER       NOT NULL DEFAULT 0,
  -- 'success' | 'partial' | 'failed'
  status          TEXT          NOT NULL,
  -- Error message or notes
  message         TEXT
);

-- ─── Helpers ──────────────────────────────────────────────────────────────────

-- Auto-update updated_at columns via trigger
CREATE OR REPLACE FUNCTION set_updated_at()
RETURNS TRIGGER LANGUAGE plpgsql AS $$
BEGIN
  NEW.updated_at = NOW();
  RETURN NEW;
END;
$$;

DO $$
BEGIN
  IF NOT EXISTS (
    SELECT 1 FROM pg_trigger WHERE tgname = 'songs_set_updated_at'
  ) THEN
    CREATE TRIGGER songs_set_updated_at
      BEFORE UPDATE ON songs
      FOR EACH ROW EXECUTE FUNCTION set_updated_at();
  END IF;

  IF NOT EXISTS (
    SELECT 1 FROM pg_trigger WHERE tgname = 'tempo_maps_set_updated_at'
  ) THEN
    CREATE TRIGGER tempo_maps_set_updated_at
      BEFORE UPDATE ON tempo_maps
      FOR EACH ROW EXECUTE FUNCTION set_updated_at();
  END IF;
END;
$$;
