-- Migration 009: notes
--
-- Notes have:
--   - color: one of 8 predefined values, or NULL (default)
--   - is_pinned + is_archived (mutually exclusive — enforced by CHECK)
--   - deleted_at: soft-delete; pg_cron purges after 7 days
--
-- Updated_by + updated_at are touched by an UPDATE trigger so the UI can show
-- "edited by X" without trusting the client.

-- ── Enum ─────────────────────────────────────────────────────────────────────

CREATE TYPE public.note_color AS ENUM (
    'yellow', 'green', 'blue', 'pink', 'purple', 'orange', 'gray', 'red'
);

-- ── notes ────────────────────────────────────────────────────────────────────

CREATE TABLE public.notes (
    id            uuid              PRIMARY KEY DEFAULT gen_random_uuid(),
    collective_id uuid              NOT NULL REFERENCES public.collectives(id) ON DELETE CASCADE,
    title         text              NULL,
    content       text              NOT NULL DEFAULT '',
    color         public.note_color NULL,
    is_pinned     boolean           NOT NULL DEFAULT false,
    is_archived   boolean           NOT NULL DEFAULT false,
    deleted_at    timestamptz       NULL,
    created_by    uuid              NOT NULL REFERENCES public.users(id) ON DELETE RESTRICT,
    created_at    timestamptz       NOT NULL DEFAULT now(),
    updated_by    uuid              NOT NULL REFERENCES public.users(id) ON DELETE RESTRICT,
    updated_at    timestamptz       NOT NULL DEFAULT now(),
    -- Pinned and archived are mutually exclusive (analysis §5.2)
    CONSTRAINT notes_pin_archive_exclusive CHECK (NOT (is_pinned AND is_archived))
);

ALTER TABLE public.notes ENABLE ROW LEVEL SECURITY;

-- Main board query: collective + status (active/pinned/archived) excluding trash
CREATE INDEX notes_collective_active_idx
    ON public.notes (collective_id, is_pinned DESC, updated_at DESC)
    WHERE deleted_at IS NULL AND is_archived = false;

CREATE INDEX notes_collective_archived_idx
    ON public.notes (collective_id, updated_at DESC)
    WHERE deleted_at IS NULL AND is_archived = true;

CREATE INDEX notes_collective_trash_idx
    ON public.notes (collective_id, deleted_at)
    WHERE deleted_at IS NOT NULL;

-- ── Trigger: refresh updated_at / updated_by on UPDATE ───────────────────────

CREATE OR REPLACE FUNCTION public.fn_notes_touch()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
    NEW.updated_at := now();
    -- updated_by is set by the client (auth.uid()); fall back to created_by if absent.
    IF NEW.updated_by IS NULL THEN
        NEW.updated_by := COALESCE(auth.uid(), OLD.updated_by);
    END IF;
    RETURN NEW;
END;
$$;

CREATE TRIGGER trg_notes_touch
    BEFORE UPDATE ON public.notes
    FOR EACH ROW EXECUTE FUNCTION public.fn_notes_touch();

-- ── RLS: notes ───────────────────────────────────────────────────────────────

-- All members (including guests) can read notes within the 7-day trash window.
CREATE POLICY notes_select
    ON public.notes FOR SELECT
    USING (
        public.is_member(collective_id)
        AND (
            deleted_at IS NULL
            OR deleted_at > now() - INTERVAL '7 days'
        )
    );

-- Active members (admin + member) can create notes.
CREATE POLICY notes_insert
    ON public.notes FOR INSERT
    WITH CHECK (
        public.is_active_member(collective_id)
        AND created_by = auth.uid()
        AND updated_by = auth.uid()
    );

-- Active members can edit any note in the collective (per analysis §5.2).
CREATE POLICY notes_update
    ON public.notes FOR UPDATE
    USING  (public.is_active_member(collective_id))
    WITH CHECK (public.is_active_member(collective_id));

-- Active members can permanently hard-delete a note only once it has been soft-deleted.
-- pg_cron also purges old trash as superuser, bypassing RLS — intentional.
CREATE POLICY notes_delete
    ON public.notes FOR DELETE
    USING (
        public.is_active_member(collective_id)
        AND deleted_at IS NOT NULL
    );

-- ── pg_cron: purge notes from trash after 7 days ─────────────────────────────
-- Defensive: ensure the extension is present (Supabase self-hosted ships with it).
CREATE EXTENSION IF NOT EXISTS pg_cron;

SELECT cron.schedule(
    'purge-deleted-notes',
    '10 3 * * *',
    $$
        DELETE FROM public.notes
        WHERE  deleted_at < now() - INTERVAL '7 days';
    $$
);
