-- t-paliad-265 / m/paliad#96 — per-event-card optional choices on the
-- Verfahrensablauf timeline.
--
-- Design: docs/design-event-card-choices-2026-05-25.md
-- Decisions: see §11 of the design doc.
--
-- Two schema changes:
--
--   1. paliad.project_event_choices — new persistence table holding the
--      user's per-card picks scoped to a project. One row per
--      (project, submission_code, choice_kind). Re-picking is an UPDATE
--      (UNIQUE constraint enforces idempotence).
--
--   2. paliad.deadline_rules.choices_offered jsonb — opt-in declaration
--      of which choice-kinds each rule offers. The projection engine
--      reads this to decide whether to render the caret affordance on
--      a card. Seeded for every event_type='decision' rule (appellant),
--      every priority='optional' rule (skip), and the two Klageerwiderung
--      rows (include_ccr).
--
-- NOTE on join key: the design doc named the join column "rule_code".
-- Live verification (2026-05-25 SELECT against paliad.deadline_rules)
-- showed `rule_code` is NULL on every decision row — it's the legal-
-- source citation column, not a stable identifier. The
-- AnchorOverrides plumbing in internal/services/fristenrechner.go
-- already keys on `submission_code` (UIDeadline.Code populates from
-- submission_code, lines 351-352), so we mirror that decision here:
-- the join column is `submission_code`. Same intent, correct field.
--
-- Idempotent: CREATE TABLE IF NOT EXISTS + ADD COLUMN IF NOT EXISTS +
-- UPDATEs guarded by WHERE choices_offered IS NULL so re-applying
-- against an already-seeded DB no-ops.

SELECT set_config(
    'paliad.audit_reason',
    'mig 129: add paliad.project_event_choices + deadline_rules.choices_offered for per-event-card optional choices (t-paliad-265 / m/paliad#96)',
    true);

-- 1. The choice-storage table ----------------------------------------------

CREATE TABLE IF NOT EXISTS paliad.project_event_choices (
    id              uuid PRIMARY KEY DEFAULT gen_random_uuid(),
    project_id      uuid NOT NULL REFERENCES paliad.projects(id) ON DELETE CASCADE,
    submission_code text NOT NULL,
    choice_kind     text NOT NULL CHECK (choice_kind IN ('appellant', 'include_ccr', 'skip')),
    choice_value    text NOT NULL,
    created_by      uuid REFERENCES paliad.users(id) ON DELETE SET NULL,
    created_at      timestamptz NOT NULL DEFAULT now(),
    updated_by      uuid REFERENCES paliad.users(id) ON DELETE SET NULL,
    updated_at      timestamptz NOT NULL DEFAULT now(),

    UNIQUE (project_id, submission_code, choice_kind)
);

CREATE INDEX IF NOT EXISTS project_event_choices_project_idx
    ON paliad.project_event_choices (project_id);

ALTER TABLE paliad.project_event_choices ENABLE ROW LEVEL SECURITY;

DROP POLICY IF EXISTS project_event_choices_select ON paliad.project_event_choices;
CREATE POLICY project_event_choices_select ON paliad.project_event_choices
    FOR SELECT USING (paliad.can_see_project(project_id));

DROP POLICY IF EXISTS project_event_choices_mutate ON paliad.project_event_choices;
CREATE POLICY project_event_choices_mutate ON paliad.project_event_choices
    FOR ALL
    USING (paliad.can_see_project(project_id))
    WITH CHECK (paliad.can_see_project(project_id));

COMMENT ON TABLE paliad.project_event_choices IS
    'Per-event-card user picks scoped to a project. choice_kind ∈ {appellant, include_ccr, skip}. '
    'choice_value namespace per kind: appellant=claimant|defendant|both|none; include_ccr=true|false; '
    'skip=true|false. Join key submission_code matches paliad.deadline_rules.submission_code (the same key '
    'AnchorOverrides uses). UNIQUE(project,submission_code,kind) keeps re-picks idempotent. '
    'Audit-logged via paliad.system_audit_log (event_type=project_event_choice.set).';

-- 2. The choices_offered opt-in column ------------------------------------

ALTER TABLE paliad.deadline_rules
    ADD COLUMN IF NOT EXISTS choices_offered jsonb;

COMMENT ON COLUMN paliad.deadline_rules.choices_offered IS
    'Declares which per-card choice-kinds this rule offers on the Verfahrensablauf timeline. '
    'NULL = no caret affordance (default). Example shapes: '
    '{"appellant": ["claimant","defendant","both","none"]} on decision rules, '
    '{"skip": [true, false]} on optional rules, '
    '{"include_ccr": [true, false]} on Klageerwiderung rules. '
    'Engine and frontend read it; storing per-kind value lists keeps the contract self-describing.';

-- 3. Seed -----------------------------------------------------------------

-- 3a. Every published decision rule offers the appellant choice.
UPDATE paliad.deadline_rules
   SET choices_offered = '{"appellant": ["claimant", "defendant", "both", "none"]}'::jsonb
 WHERE event_type = 'decision'
   AND lifecycle_state = 'published'
   AND choices_offered IS NULL;

-- 3b. Every published optional rule offers the skip choice.
UPDATE paliad.deadline_rules
   SET choices_offered = '{"skip": [true, false]}'::jsonb
 WHERE priority = 'optional'
   AND lifecycle_state = 'published'
   AND choices_offered IS NULL;

-- 3c. Klageerwiderung rules offer the include_ccr choice. Two rows
-- today (upc.inf.cfi.sod + de.inf.lg.erwidg) — verified live
-- (2026-05-25 SELECT FROM paliad.deadline_rules WHERE name ILIKE
-- 'Klageerwiderung'); the UPC INF Klageerwiderung is `sod` (Statement
-- of Defence, R.24 RoP), not `def`. Slice B (Q4 bundle) is the
-- user-visible feature.
UPDATE paliad.deadline_rules
   SET choices_offered = '{"include_ccr": [true, false]}'::jsonb
 WHERE submission_code IN ('upc.inf.cfi.sod', 'de.inf.lg.erwidg')
   AND lifecycle_state = 'published'
   AND choices_offered IS NULL;
