-- Reports page foundation. Part of the locked /reports page design
-- (docs/reports-page-design.md). Three pieces:
--   1. Extend the existing report_templates with visibility + archive flag.
--   2. Append-only report_runs audit log.
--   3. report_schedules driving the BullMQ recurring scheduler.

-- ─── 1. Extend report_templates ─────────────────────────────────────────────
ALTER TABLE report_templates
  ADD COLUMN IF NOT EXISTS description text,
  ADD COLUMN IF NOT EXISTS visibility text NOT NULL DEFAULT 'private',
  ADD COLUMN IF NOT EXISTS archived_at timestamptz;

CREATE INDEX IF NOT EXISTS idx_report_templates_port_visibility
  ON report_templates(port_id, visibility);

-- Soften the unique-name constraint so archived templates don't block reuse
-- of a name. Drop the existing index + recreate with a WHERE clause.
DROP INDEX IF EXISTS uniq_report_templates_port_kind_name;
CREATE UNIQUE INDEX uniq_report_templates_port_kind_name
  ON report_templates(port_id, kind, LOWER(name))
  WHERE archived_at IS NULL;

-- ─── 2. report_runs (append-only audit log) ─────────────────────────────────
CREATE TABLE IF NOT EXISTS report_runs (
  id                    text PRIMARY KEY DEFAULT gen_random_uuid()::text,
  port_id               text NOT NULL REFERENCES ports(id) ON DELETE CASCADE,
  -- Nullable: ad-hoc runs (no template) still get logged.
  template_id           text REFERENCES report_templates(id) ON DELETE SET NULL,
  -- Forward-declared FK; populated once report_schedules is created below.
  schedule_id           text,
  kind                  text NOT NULL,
  -- Snapshotted at run time so re-runs reproduce identically even if the
  -- source template has since been edited / archived.
  config                jsonb NOT NULL,
  output_format         text NOT NULL,    -- 'pdf' | 'csv' | 'png' | 'jpg'
  -- Storage key of the rendered artefact. Same backend as files (s3 or fs).
  storage_key           text,
  size_bytes            integer,
  status                text NOT NULL DEFAULT 'pending',  -- pending | rendering | complete | failed
  error_message         text,
  triggered_by          text NOT NULL,    -- 'user' | 'schedule'
  triggered_by_user_id  text REFERENCES "user"(id) ON DELETE SET NULL,
  -- When non-null, this run was emailed to these recipients on completion.
  emailed_to            jsonb,            -- Array<{ name?: string, email: string }>
  emailed_at            timestamptz,
  created_at            timestamptz NOT NULL DEFAULT now(),
  completed_at          timestamptz
);

CREATE INDEX IF NOT EXISTS report_runs_port_created_idx
  ON report_runs(port_id, created_at DESC);
CREATE INDEX IF NOT EXISTS report_runs_port_user_idx
  ON report_runs(port_id, triggered_by_user_id);
CREATE INDEX IF NOT EXISTS report_runs_port_template_idx
  ON report_runs(port_id, template_id)
  WHERE template_id IS NOT NULL;

-- ─── 3. report_schedules (BullMQ recurring scheduler) ────────────────────────
CREATE TABLE IF NOT EXISTS report_schedules (
  id              text PRIMARY KEY DEFAULT gen_random_uuid()::text,
  port_id         text NOT NULL REFERENCES ports(id) ON DELETE CASCADE,
  template_id     text NOT NULL REFERENCES report_templates(id) ON DELETE CASCADE,
  -- Enum cadence at v1; cron strings can layer on top later.
  cadence         text NOT NULL,
  recipients      jsonb NOT NULL,            -- Array<{ name?: string, email: string }>
  output_format   text NOT NULL DEFAULT 'pdf',
  enabled         boolean NOT NULL DEFAULT true,
  last_run_at     timestamptz,
  next_run_at     timestamptz NOT NULL,
  created_by      text NOT NULL REFERENCES "user"(id) ON DELETE RESTRICT,
  created_at      timestamptz NOT NULL DEFAULT now(),
  updated_at      timestamptz NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS report_schedules_port_enabled_next_idx
  ON report_schedules(port_id, enabled, next_run_at);

-- Now wire the forward-declared schedule_id FK from report_runs back to the
-- schedules table.
ALTER TABLE report_runs
  ADD CONSTRAINT report_runs_schedule_id_fkey
  FOREIGN KEY (schedule_id) REFERENCES report_schedules(id) ON DELETE SET NULL;
