-- Reminder system redesign (t-paliad-064).
--
-- Three things land here, in service of the new "zero-overdue SLO" model:
--
-- 1. paliad.users gets two new columns:
--      * reminder_warning_offset_days — how many days before each deadline
--        the +N-day warning email fires. Default 7 matches the prior
--        Monday-weekly-digest behaviour. Per-user customisable on the
--        Settings → Notifications page.
--      * escalation_contact_id — optional pointer to another paliad.users
--        row that should also be cc'd on overdue / DRINGEND emails. NULL
--        means "fall back to global_admins" (the default escalation
--        channel). The Settings UI dropdown is a follow-up task; the
--        column ships now to avoid a second migration when wiring lands.
--
-- 2. paliad.reminder_log gains slot + slot_date for digest dedup. The new
--    service writes one row per (user_id, slot, slot_date), enforced by a
--    partial UNIQUE index. Legacy per-deadline rows (slot IS NULL) coexist
--    and are ignored by the new dedup index — they're kept on disk for
--    audit and a separate housekeeping migration will prune them once the
--    new path has soaked.
--
-- 3. The reminder_type CHECK constraint widens to admit the two new
--    digest values ('morning_digest', 'evening_digest'). Existing values
--    ('overdue', 'tomorrow', 'weekly') stay valid so the legacy code path
--    can run alongside during deploy if needed.
--
-- All operations are idempotent (IF NOT EXISTS on columns and index;
-- DROP/RE-ADD on the named constraints) so a re-run is safe.

-- 1) Per-user warning offset (default 7).
ALTER TABLE paliad.users
    ADD COLUMN IF NOT EXISTS reminder_warning_offset_days
        INT NOT NULL DEFAULT 7;

-- Range check: 1..30. A 0-day "warning" is just the same as the morning
-- reminder, and 30+ days is so far out the email becomes noise.
ALTER TABLE paliad.users
    DROP CONSTRAINT IF EXISTS users_reminder_warning_offset_check;
ALTER TABLE paliad.users
    ADD CONSTRAINT users_reminder_warning_offset_check
    CHECK (reminder_warning_offset_days BETWEEN 1 AND 30);

-- 2) Optional escalation contact. ON DELETE SET NULL so deleting the
--    chosen escalation user doesn't cascade-delete the source user — they
--    just lose their override and fall back to global_admins.
ALTER TABLE paliad.users
    ADD COLUMN IF NOT EXISTS escalation_contact_id UUID
        REFERENCES paliad.users(id) ON DELETE SET NULL;

-- A user can't be their own escalation contact (would just bounce mail
-- back to themselves on overdue).
ALTER TABLE paliad.users
    DROP CONSTRAINT IF EXISTS users_escalation_contact_self_check;
ALTER TABLE paliad.users
    ADD CONSTRAINT users_escalation_contact_self_check
    CHECK (escalation_contact_id IS NULL OR escalation_contact_id <> id);

-- 3) Slot-based dedup on reminder_log.
ALTER TABLE paliad.reminder_log
    ADD COLUMN IF NOT EXISTS slot      TEXT,
    ADD COLUMN IF NOT EXISTS slot_date DATE;

-- slot must be 'morning' | 'evening' when present (NULL = legacy row).
ALTER TABLE paliad.reminder_log
    DROP CONSTRAINT IF EXISTS reminder_log_slot_check;
ALTER TABLE paliad.reminder_log
    ADD CONSTRAINT reminder_log_slot_check
    CHECK (slot IS NULL OR slot IN ('morning', 'evening'));

-- Widen the reminder_type CHECK to admit the new digest values. Keeps the
-- legacy values valid so coexistence during deploy is harmless.
ALTER TABLE paliad.reminder_log
    DROP CONSTRAINT IF EXISTS reminder_log_reminder_type_check;
ALTER TABLE paliad.reminder_log
    ADD CONSTRAINT reminder_log_reminder_type_check
    CHECK (reminder_type IN (
        'overdue', 'tomorrow', 'weekly',
        'morning_digest', 'evening_digest'
    ));

-- Partial unique index — one digest row per (user, slot, local-date).
-- Partial on slot IS NOT NULL so legacy rows (which have NULL slot) don't
-- conflict with the new model.
CREATE UNIQUE INDEX IF NOT EXISTS reminder_log_slot_dedup_idx
    ON paliad.reminder_log (user_id, slot, slot_date)
    WHERE slot IS NOT NULL;
