-- t-paliad-199 / Fristen Phase 3 Slice 9 follow-up A — drop the legacy
-- Pipeline-C source tables (paliad.event_deadlines +
-- paliad.event_deadline_rule_codes) and the read-only trigger from
-- mig 086, now that EventDeadlineService.Calculate has been rewritten
-- to read from paliad.deadline_rules.
--
-- Lorenz's Slice 9 (t-paliad-195) deferred this drop because the
-- legacy service still SELECTed event_deadlines.duration_value /
-- duration_unit / timing / notes / alt_* / combine_op. Slice 9
-- follow-up A refactors the service onto deadline_rules (the unified
-- source-of-truth since Slice 3 / mig 085) and frees us to remove the
-- old tables.
--
-- Sequencing — every step in this single migration is required for the
-- drop to be safe:
--
--   1. Snapshot both source tables into paliad.event_deadlines_pre_092
--      + paliad.event_deadline_rule_codes_pre_092 (CREATE TABLE IF NOT
--      EXISTS — idempotent re-run). The snapshots persist after the
--      drop as audit anchors; the down migration restores from them.
--   2. ADD COLUMN rule_codes text[] to paliad.deadline_rules and
--      backfill from paliad.event_deadline_rule_codes. Pipeline-C
--      deadlines carry multi-code rules (e.g. R.198 / R.213 carry
--      [RoP.029.a, RoP.030]) which don't fit deadline_rules.rule_code
--      (singular text); mig 085 left rule_code NULL on the 77
--      Pipeline-C rows. Without this backfill the drop would silently
--      lose 72 RoP citations.
--   3. Hard assertion: every event_deadline_rule_codes row resolves to
--      a deadline_rules row via the sequence_order = 1000 +
--      event_deadlines.id convention from mig 085. If any row didn't
--      land, fail loudly before dropping the source.
--   4. DROP TRIGGER + FUNCTION from mig 086 — orphan once the table is
--      gone.
--   5. DROP TABLE paliad.event_deadline_rule_codes (FK side first).
--   6. DROP TABLE paliad.event_deadlines.
--   7. Final assertion: paliad.deadline_rules still carries >=77 active
--      rows with trigger_event_id IS NOT NULL (the Slice 3 corpus must
--      not have collapsed).
--
-- audit_reason wrapper at top — the mig 079 trigger on
-- paliad.deadline_rules logs every row-level edit. The ALTER TABLE +
-- UPDATE on rule_codes fires through that trigger, so the reason
-- persists in paliad.deadline_rule_audit for forever-grade audit.

SELECT set_config(
    'paliad.audit_reason',
    'mig 092: drop paliad.event_deadlines + event_deadline_rule_codes after backfilling rule_codes into deadline_rules (t-paliad-199, Slice 9 follow-up A, design §3.E)',
    true);

-- =============================================================================
-- 1. Backup snapshots — full row copies so the down migration can
--    rebuild both tables byte-identically. CREATE TABLE IF NOT EXISTS
--    keeps the migration idempotent across reapplications; if the
--    snapshot already exists from a prior aborted run, we re-use it.
-- =============================================================================

CREATE TABLE IF NOT EXISTS paliad.event_deadlines_pre_092 AS
SELECT *, now() AS snapshotted_at
  FROM paliad.event_deadlines;

COMMENT ON TABLE paliad.event_deadlines_pre_092 IS
    'Snapshot of paliad.event_deadlines before mig 092 dropped it. '
    'Source-of-truth for the down migration; persists post-drop as the '
    'permanent audit record of the 77 Pipeline-C source rows that '
    'seeded paliad.deadline_rules via mig 085. Drop with a focused '
    'follow-up after Slice 9 is verified in prod (pair with '
    'paliad.deadline_rules_pre_091 cleanup).';

CREATE TABLE IF NOT EXISTS paliad.event_deadline_rule_codes_pre_092 AS
SELECT *, now() AS snapshotted_at
  FROM paliad.event_deadline_rule_codes;

COMMENT ON TABLE paliad.event_deadline_rule_codes_pre_092 IS
    'Snapshot of paliad.event_deadline_rule_codes before mig 092 dropped '
    'it. Restored by the down migration; persists post-drop as the '
    'permanent audit record of the legacy RoP citations attached to '
    'Pipeline-C deadlines (72 rows across 70 of 77 deadlines).';

-- =============================================================================
-- 2. Add paliad.deadline_rules.rule_codes (text[]) and backfill it for
--    the 77 Pipeline-C rules. Mig 085 set rule_code = NULL on every
--    Pipeline-C row because deadline_rules.rule_code is singular and
--    Pipeline-C deadlines can carry multiple citations. rule_codes
--    holds the array form. Pipeline-A rules keep NULL here and continue
--    using rule_code; this column is a Pipeline-C-only field today.
-- =============================================================================

ALTER TABLE paliad.deadline_rules
    ADD COLUMN IF NOT EXISTS rule_codes text[];

COMMENT ON COLUMN paliad.deadline_rules.rule_codes IS
    'Array of legal-rule citations attached to this deadline, in '
    'render order. Pipeline-C rules (event-rooted, trigger_event_id IS '
    'NOT NULL) populate this column from the legacy '
    'paliad.event_deadline_rule_codes junction (mig 092 backfill); '
    'Pipeline-A rules use the singular rule_code column instead. NULL '
    'on Pipeline-A rules + on the 7 Pipeline-C deadlines that had no '
    'junction rows pre-mig.';

-- Aggregate junction rows into a text[] sorted by (sort_order,
-- rule_code) — matches the legacy ORDER BY contract that
-- EventDeadlineService.loadRuleCodes used.
--
-- Join key: the sequence_order = 1000 + event_deadlines.id convention
-- mig 085 anchored. Every active event_deadlines.id has a corresponding
-- deadline_rules row at sequence_order = 1000 + id; mig 085's hard
-- assertion guarantees that.
WITH agg AS (
    SELECT event_deadline_id,
           array_agg(rule_code ORDER BY sort_order, rule_code) AS codes
      FROM paliad.event_deadline_rule_codes
     GROUP BY event_deadline_id
)
UPDATE paliad.deadline_rules dr
   SET rule_codes = agg.codes
  FROM agg
 WHERE dr.trigger_event_id IS NOT NULL
   AND dr.sequence_order = 1000 + agg.event_deadline_id
   AND dr.rule_codes IS DISTINCT FROM agg.codes;

-- =============================================================================
-- 3. Hard assertion: every junction row landed on a deadline_rules row.
--    Sums elements across all rule_codes arrays — if the count differs
--    from the source junction count, some event_deadline_id failed to
--    match any deadline_rules row (sequence_order convention broken).
--    Fail loudly here BEFORE dropping the source.
-- =============================================================================

DO $$
DECLARE
    n_codes_src     int;
    n_codes_target  int;
BEGIN
    SELECT count(*) INTO n_codes_src
      FROM paliad.event_deadline_rule_codes;

    SELECT COALESCE(SUM(array_length(rule_codes, 1)), 0) INTO n_codes_target
      FROM paliad.deadline_rules
     WHERE rule_codes IS NOT NULL;

    RAISE NOTICE 'mig 092: junction rows=%, backfilled rule_codes elements=%',
                 n_codes_src, n_codes_target;

    IF n_codes_target < n_codes_src THEN
        RAISE EXCEPTION 'mig 092: rule_codes backfill missed % junction rows '
                        '(source=%, target=%) — sequence_order = 1000 + ed.id '
                        'convention broken? Aborting before drop.',
                        n_codes_src - n_codes_target, n_codes_src, n_codes_target;
    END IF;
END $$;

-- =============================================================================
-- 4. Drop the read-only trigger + function from mig 086. They're orphan
--    once paliad.event_deadlines goes away — explicit drop documents
--    that the wrapper's job is done, and keeps the symmetric reverse in
--    the down migration cleanly readable.
-- =============================================================================

DROP TRIGGER IF EXISTS event_deadlines_readonly ON paliad.event_deadlines;
DROP FUNCTION IF EXISTS paliad.event_deadlines_readonly_trigger();

-- =============================================================================
-- 5. Drop the legacy tables. Order: junction first (it has a FK to
--    event_deadlines), then the parent. Explicit ordering is clearer
--    than relying on CASCADE and mirrors the down migration's CREATE
--    sequence.
-- =============================================================================

DROP TABLE IF EXISTS paliad.event_deadline_rule_codes;
DROP TABLE IF EXISTS paliad.event_deadlines;

-- =============================================================================
-- 6. Final assertion: the unified Pipeline-C corpus is still intact.
--    Mig 085 moved 77 active rows; future hand-edited Pipeline-C rules
--    can only raise the count. A drop below 77 means the upstream
--    deadline_rules data was clobbered while this migration ran and
--    the deploy must abort.
-- =============================================================================

DO $$
DECLARE
    n_unified int;
BEGIN
    SELECT count(*) INTO n_unified
      FROM paliad.deadline_rules
     WHERE trigger_event_id IS NOT NULL AND is_active = true;

    RAISE NOTICE 'mig 092: post-drop Pipeline-C rule count = %', n_unified;

    IF n_unified < 77 THEN
        RAISE EXCEPTION 'mig 092: Pipeline-C corpus collapsed — expected >=77 '
                        'active deadline_rules with trigger_event_id IS NOT NULL, got %',
                        n_unified;
    END IF;
END $$;
