-- t-paliad-206 / proceeding-code rename — replace the historical
-- UPPER_SNAKE proceeding codes with the lowercase dot-separated
-- taxonomy ratified by m on 2026-05-18 (see
-- docs/design-proceeding-code-taxonomy-2026-05-18.md).
--
-- IDs are stable. Only the `code` STRING changes. FKs
-- (deadline_rules.proceeding_type_id, projects.proceeding_type_id,
-- deadline_rules.spawn_proceeding_type_id) reference IDs, so the
-- existing rule corpus and spawn wiring continue to work unchanged
-- (incl. mig 095's spawn_proceeding_type_id=11 which becomes
-- 'upc.apl.merits' after this migration).
--
-- Soft references on `code` (text column on event_category_concepts) are
-- updated row-for-row to keep the soft join through proceeding_types.code
-- resolving.
--
-- The materialized view paliad.deadline_search projects pt.code as
-- proceeding_code; mig 096 REFRESHes it at the bottom so the new codes
-- show up in search results immediately.
--
-- Idempotent:
--   * UPDATEs are guarded by `WHERE code = '<OLD>'`. Re-running after a
--     successful first apply is a no-op.
--   * INSERT of upc.ccr.cfi uses `WHERE NOT EXISTS` keyed on the new
--     code (bohr noted in t-paliad-205 that a UNIQUE constraint on the
--     code column is not present, hence WHERE NOT EXISTS rather than
--     ON CONFLICT).
--   * CHECK constraint is dropped-then-recreated under the same name
--     (paliad_proceeding_code_shape) so reapplication doesn't error.
--   * Snapshot table uses CREATE TABLE IF NOT EXISTS.
--
-- audit_reason wrapper required by the mig 079 audit trigger.

SELECT set_config(
    'paliad.audit_reason',
    'mig 096: t-paliad-206 proceeding-code rename — lowercase dot-separated taxonomy + new upc.ccr.cfi illustrative peer; see docs/design-proceeding-code-taxonomy-2026-05-18.md',
    true);

-- =============================================================================
-- 1. Backup snapshot of paliad.proceeding_types BEFORE the rename. The
--    rename is forward-only in code (the Go + frontend sweeps reference
--    the new strings) but the DB snapshot is the audit anchor and the
--    source for the down migration.
-- =============================================================================

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

COMMENT ON TABLE paliad.proceeding_types_pre_096 IS
    'Snapshot of paliad.proceeding_types taken before mig 096 renamed '
    'the `code` strings to the lowercase dot-separated taxonomy '
    '(t-paliad-206, 2026-05-18). Source-of-truth for the down '
    'migration; persists post-rename as the permanent audit record.';

-- =============================================================================
-- 2. Drop any prior shape CHECK so we can recreate it post-rename. The
--    constraint name is stable so reapplication idempotently drops it.
-- =============================================================================

ALTER TABLE paliad.proceeding_types
    DROP CONSTRAINT IF EXISTS paliad_proceeding_code_shape;

-- =============================================================================
-- 3. The 19 renames. Order-independent — every UPDATE is guarded by
--    `WHERE code = '<OLD>'` so re-application is a no-op. id values in
--    the trailing comment for cross-reference with the design doc.
-- =============================================================================

-- UPC
UPDATE paliad.proceeding_types SET code = 'upc.inf.cfi'    WHERE code = 'UPC_INF';        -- id=8
UPDATE paliad.proceeding_types SET code = 'upc.rev.cfi'    WHERE code = 'UPC_REV';        -- id=9
UPDATE paliad.proceeding_types SET code = 'upc.pi.cfi'     WHERE code = 'UPC_PI';         -- id=10
UPDATE paliad.proceeding_types SET code = 'upc.apl.merits' WHERE code = 'UPC_APP';        -- id=11
UPDATE paliad.proceeding_types SET code = 'upc.dmgs.cfi'   WHERE code = 'UPC_DAMAGES';    -- id=17
UPDATE paliad.proceeding_types SET code = 'upc.disc.cfi'   WHERE code = 'UPC_DISCOVERY';  -- id=18
UPDATE paliad.proceeding_types SET code = 'upc.apl.cost'   WHERE code = 'UPC_COST_APPEAL';-- id=19
UPDATE paliad.proceeding_types SET code = 'upc.apl.order'  WHERE code = 'UPC_APP_ORDERS'; -- id=20

-- DE
UPDATE paliad.proceeding_types SET code = 'de.inf.lg'      WHERE code = 'DE_INF';         -- id=12
UPDATE paliad.proceeding_types SET code = 'de.inf.olg'     WHERE code = 'DE_INF_OLG';     -- id=25
UPDATE paliad.proceeding_types SET code = 'de.inf.bgh'     WHERE code = 'DE_INF_BGH';     -- id=26
UPDATE paliad.proceeding_types SET code = 'de.null.bpatg'  WHERE code = 'DE_NULL';        -- id=13
UPDATE paliad.proceeding_types SET code = 'de.null.bgh'    WHERE code = 'DE_NULL_BGH';    -- id=27

-- EPA
UPDATE paliad.proceeding_types SET code = 'epa.grant.exa'  WHERE code = 'EP_GRANT';       -- id=16
UPDATE paliad.proceeding_types SET code = 'epa.opp.opd'    WHERE code = 'EPA_OPP';        -- id=14
UPDATE paliad.proceeding_types SET code = 'epa.opp.boa'    WHERE code = 'EPA_APP';        -- id=15

-- DPMA
UPDATE paliad.proceeding_types SET code = 'dpma.opp.dpma'     WHERE code = 'DPMA_OPP';              -- id=28
UPDATE paliad.proceeding_types SET code = 'dpma.appeal.bpatg' WHERE code = 'DPMA_BPATG_BESCHWERDE';-- id=29
UPDATE paliad.proceeding_types SET code = 'dpma.appeal.bgh'   WHERE code = 'DPMA_BGH_RB';          -- id=30

-- =============================================================================
-- 4. Update soft references on event_category_concepts.proceeding_type_code.
--    Same OLD→NEW table as above; the column has a UNIQUE NULLS NOT
--    DISTINCT constraint on (event_category_id, concept_id, proceeding_type_code)
--    but no row has the NEW string yet so the UPDATEs cannot collide.
-- =============================================================================

-- UPC
UPDATE paliad.event_category_concepts SET proceeding_type_code = 'upc.inf.cfi'    WHERE proceeding_type_code = 'UPC_INF';
UPDATE paliad.event_category_concepts SET proceeding_type_code = 'upc.rev.cfi'    WHERE proceeding_type_code = 'UPC_REV';
UPDATE paliad.event_category_concepts SET proceeding_type_code = 'upc.pi.cfi'     WHERE proceeding_type_code = 'UPC_PI';
UPDATE paliad.event_category_concepts SET proceeding_type_code = 'upc.apl.merits' WHERE proceeding_type_code = 'UPC_APP';
UPDATE paliad.event_category_concepts SET proceeding_type_code = 'upc.dmgs.cfi'   WHERE proceeding_type_code = 'UPC_DAMAGES';
UPDATE paliad.event_category_concepts SET proceeding_type_code = 'upc.disc.cfi'   WHERE proceeding_type_code = 'UPC_DISCOVERY';
UPDATE paliad.event_category_concepts SET proceeding_type_code = 'upc.apl.cost'   WHERE proceeding_type_code = 'UPC_COST_APPEAL';
UPDATE paliad.event_category_concepts SET proceeding_type_code = 'upc.apl.order'  WHERE proceeding_type_code = 'UPC_APP_ORDERS';

-- DE
UPDATE paliad.event_category_concepts SET proceeding_type_code = 'de.inf.lg'      WHERE proceeding_type_code = 'DE_INF';
UPDATE paliad.event_category_concepts SET proceeding_type_code = 'de.inf.olg'     WHERE proceeding_type_code = 'DE_INF_OLG';
UPDATE paliad.event_category_concepts SET proceeding_type_code = 'de.inf.bgh'     WHERE proceeding_type_code = 'DE_INF_BGH';
UPDATE paliad.event_category_concepts SET proceeding_type_code = 'de.null.bpatg'  WHERE proceeding_type_code = 'DE_NULL';
UPDATE paliad.event_category_concepts SET proceeding_type_code = 'de.null.bgh'    WHERE proceeding_type_code = 'DE_NULL_BGH';

-- EPA
UPDATE paliad.event_category_concepts SET proceeding_type_code = 'epa.grant.exa'  WHERE proceeding_type_code = 'EP_GRANT';
UPDATE paliad.event_category_concepts SET proceeding_type_code = 'epa.opp.opd'    WHERE proceeding_type_code = 'EPA_OPP';
UPDATE paliad.event_category_concepts SET proceeding_type_code = 'epa.opp.boa'    WHERE proceeding_type_code = 'EPA_APP';

-- DPMA
UPDATE paliad.event_category_concepts SET proceeding_type_code = 'dpma.opp.dpma'     WHERE proceeding_type_code = 'DPMA_OPP';
UPDATE paliad.event_category_concepts SET proceeding_type_code = 'dpma.appeal.bpatg' WHERE proceeding_type_code = 'DPMA_BPATG_BESCHWERDE';
UPDATE paliad.event_category_concepts SET proceeding_type_code = 'dpma.appeal.bgh'   WHERE proceeding_type_code = 'DPMA_BGH_RB';

-- =============================================================================
-- 5. Insert the new illustrative peer `upc.ccr.cfi`. is_active=true so it
--    surfaces in the determinator + dropdowns; no rules attached.
--    proceeding_mapping.go routes cascade hits on this code back to
--    upc.inf.cfi (id=8) with the with_ccr default flag — see design doc S1.
--
--    WHERE NOT EXISTS gates the insert on the new code so re-application
--    is a no-op even though there's no UNIQUE constraint on (code).
-- =============================================================================

INSERT INTO paliad.proceeding_types
    (code, category, jurisdiction, is_active, name, name_en, description)
SELECT
    'upc.ccr.cfi',
    'fristenrechner',
    'UPC',
    true,
    'Widerklage auf Nichtigkeit',
    'Counterclaim for Revocation',
    'Illustrativer Peer von upc.inf.cfi für Widerklagen auf Nichtigkeit. Regeln liegen auf upc.inf.cfi (with_ccr=true); der Fristenrechner leitet bei Auswahl dorthin weiter. Keine eigenen Fristregeln.'
WHERE NOT EXISTS (
    SELECT 1 FROM paliad.proceeding_types
     WHERE code = 'upc.ccr.cfi');

-- =============================================================================
-- 6. CHECK constraint on the code shape. Active rows must conform to the
--    new lowercase dot-separated form; the carve-out for
--    `_archived_litigation` keeps the Pipeline-A bucket addressable.
-- =============================================================================

ALTER TABLE paliad.proceeding_types
    ADD CONSTRAINT paliad_proceeding_code_shape
    CHECK (
        code ~ '^[a-z]+\.[a-z]+\.[a-z]+$'
        OR code ~ '^_archived_'
    );

-- =============================================================================
-- 7. Refresh the deadline_search materialized view so search hits return
--    the new proceeding_code strings immediately.
-- =============================================================================

REFRESH MATERIALIZED VIEW paliad.deadline_search;

-- =============================================================================
-- 8. Hard assertions. Half-applied migrations would leave the rule corpus
--    inconsistent with the new shape; assert every active fristenrechner
--    code conforms and that no old codes leak.
-- =============================================================================

DO $$
DECLARE
    v_new_shape integer;
    v_old_codes integer;
    v_ccr_row   integer;
BEGIN
    -- 8.1 Every active fristenrechner row matches the new shape regex.
    --     20 = 19 renamed rows + 1 newly inserted upc.ccr.cfi. The check
    --     uses >= so an additional row added in a follow-up migration
    --     doesn't trip the assertion.
    SELECT count(*) INTO v_new_shape
      FROM paliad.proceeding_types
     WHERE category = 'fristenrechner'
       AND is_active = true
       AND code ~ '^[a-z]+\.[a-z]+\.[a-z]+$';
    IF v_new_shape < 20 THEN
        RAISE EXCEPTION
            'mig 096: expected >= 20 active fristenrechner rows on the new shape, got %',
            v_new_shape;
    END IF;

    -- 8.2 No old UPPER_SNAKE codes remain on any row.
    SELECT count(*) INTO v_old_codes
      FROM paliad.proceeding_types
     WHERE code LIKE 'UPC\_%' ESCAPE '\'
        OR code LIKE 'DE\_%'  ESCAPE '\'
        OR code LIKE 'EPA\_%' ESCAPE '\'
        OR code LIKE 'EP\_%'  ESCAPE '\'
        OR code LIKE 'DPMA\_%' ESCAPE '\';
    IF v_old_codes <> 0 THEN
        RAISE EXCEPTION
            'mig 096: expected 0 old UPPER_SNAKE codes after rename, got %',
            v_old_codes;
    END IF;

    -- 8.3 The new ccr peer exists and is active.
    SELECT count(*) INTO v_ccr_row
      FROM paliad.proceeding_types
     WHERE code = 'upc.ccr.cfi'
       AND is_active = true;
    IF v_ccr_row <> 1 THEN
        RAISE EXCEPTION
            'mig 096: expected 1 active upc.ccr.cfi row, got %',
            v_ccr_row;
    END IF;
END $$;
