-- 0016_views.sql
--
-- Phase 5i Slice D: persistent saved views.
--
-- A saved view bundles (filter + view_type + sort + group_by) under a
-- name. Page-agnostic per m's Q2 pick (2026-05-26) — the view doesn't
-- own a route; `is_default_for` lets one view become the auto-applied
-- default for a given page.
--
-- Singleton user; no `user_id` column. If multi-user ever lands, the
-- two partial unique indexes below need a `(user_id, …)` prefix.

CREATE TABLE IF NOT EXISTS projax.views (
  id              uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  name            text NOT NULL,
  description     text,
  filter_json     jsonb NOT NULL DEFAULT '{}'::jsonb,
  view_type       text NOT NULL,
  sort_field      text,
  sort_dir        text,
  group_by        text,
  pinned          boolean NOT NULL DEFAULT false,
  is_default_for  text,
  created_at      timestamptz NOT NULL DEFAULT now(),
  updated_at      timestamptz NOT NULL DEFAULT now(),
  deleted_at      timestamptz,
  CONSTRAINT views_view_type_chk
    CHECK (view_type IN ('card','list','calendar','kanban','timeline')),
  CONSTRAINT views_sort_dir_chk
    CHECK (sort_dir IS NULL OR sort_dir IN ('asc','desc')),
  CONSTRAINT views_kanban_needs_group
    CHECK (view_type <> 'kanban' OR group_by IS NOT NULL),
  CONSTRAINT views_default_for_chk
    CHECK (is_default_for IS NULL OR is_default_for IN ('tree','dashboard','calendar','timeline'))
);

-- Case-insensitive uniqueness on the visible name. Soft-deleted rows are
-- exempt so a re-create after delete doesn't collide.
CREATE UNIQUE INDEX IF NOT EXISTS views_name_uniq
  ON projax.views (lower(name))
  WHERE deleted_at IS NULL;

-- One default view per page. The handler should clear the prior default in
-- the same transaction as setting a new one; the index defends against any
-- code path that forgets.
CREATE UNIQUE INDEX IF NOT EXISTS views_default_for_uniq
  ON projax.views (is_default_for)
  WHERE is_default_for IS NOT NULL AND deleted_at IS NULL;

-- updated_at trigger mirrors the items table pattern.
CREATE OR REPLACE FUNCTION projax.views_touch_updated_at()
  RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
  NEW.updated_at := now();
  RETURN NEW;
END;
$$;

DROP TRIGGER IF EXISTS views_touch_updated_at ON projax.views;
CREATE TRIGGER views_touch_updated_at
  BEFORE UPDATE ON projax.views
  FOR EACH ROW EXECUTE FUNCTION projax.views_touch_updated_at();

DO $own$ BEGIN
  IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'projax_admin') THEN
    EXECUTE 'ALTER TABLE projax.views OWNER TO projax_admin';
    EXECUTE 'ALTER FUNCTION projax.views_touch_updated_at() OWNER TO projax_admin';
    EXECUTE 'GRANT SELECT, INSERT, UPDATE, DELETE ON projax.views TO projax_admin';
  END IF;
END $own$;
