-- 134_berufung_unification — Slice B1, m/paliad#124, t-paliad-298+
--
-- Collapses the 3 active UPC appeal proceeding_types (upc.apl.merits,
-- upc.apl.cost, upc.apl.order — 16 rules across 3 codes) into ONE
-- unified upc.apl proceeding type + an `appeal_target` discriminator on
-- both proceeding_types (top-level marker) and deadline_rules
-- (per-row applies-to set, text[] for multi-target rules).
--
-- ADDITIVE ONLY. The migration:
--   1. Adds the two columns + check constraints.
--   2. Inserts the new upc.apl proceeding type.
--   3. Audit-first: NOTICES every row about to be touched.
--   4. Reassigns rule rows from the 3 old types to upc.apl, stamping
--      applies_to_target by source proceeding code.
--   5. Archives (is_active=false) the 3 old proceeding_types — NEVER
--      deletes them, so any historical project_event_choices / FK
--      references stay intact.
--
-- Schadensbemessung + Bucheinsicht get NO rule rows in this migration
-- (m's 2026-05-26 decision: distinct rule sets, not shared with
-- merits). Their appeal_target enum values are defined and addressable
-- by CalcOptions.AppealTarget; the engine returns an empty timeline
-- until rules are seeded in a follow-up slice (likely via
-- /admin/rules, pairing with t-paliad-193 orphan-concept-seed).
--
-- See docs/design-litigation-planner-2026-05-26.md §18.1.

-- ---------------------------------------------------------------
-- 0. Audit reason (required by mig 079 trigger for any UPDATE on
--    paliad.deadline_rules — step 4 reassigns 16 rules).
-- ---------------------------------------------------------------

SELECT set_config(
    'paliad.audit_reason',
    'mig 134: t-paliad-292 Slice B1 — Berufung unification, collapse 3 UPC appeal proceeding_types into upc.apl.unified + appeal_target discriminator',
    true);

-- ---------------------------------------------------------------
-- 1. Schema additions
-- ---------------------------------------------------------------

ALTER TABLE paliad.proceeding_types
    ADD COLUMN appeal_target text NULL;

ALTER TABLE paliad.proceeding_types
    ADD CONSTRAINT proceeding_types_appeal_target_chk
        CHECK (appeal_target IS NULL OR appeal_target IN (
            'endentscheidung',
            'kostenentscheidung',
            'anordnung',
            'schadensbemessung',
            'bucheinsicht'
        ));

COMMENT ON COLUMN paliad.proceeding_types.appeal_target IS
    'Top-level appeal-target marker. NULL on non-appeal proceedings. '
    'Reserved for future variants — today only the unified upc.apl row '
    'has this NULL (the actual per-rule target set lives on '
    'paliad.deadline_rules.applies_to_target).';

ALTER TABLE paliad.deadline_rules
    ADD COLUMN applies_to_target text[] NULL;

ALTER TABLE paliad.deadline_rules
    ADD CONSTRAINT deadline_rules_applies_to_target_chk
        CHECK (
            applies_to_target IS NULL
            OR applies_to_target <@ ARRAY[
                'endentscheidung',
                'kostenentscheidung',
                'anordnung',
                'schadensbemessung',
                'bucheinsicht'
            ]::text[]
        );

COMMENT ON COLUMN paliad.deadline_rules.applies_to_target IS
    'Set of appeal_target slugs this rule applies to. NULL on rules '
    'that don''t belong to an appeal proceeding. The engine filters '
    'by CalcOptions.AppealTarget — rules whose applies_to_target '
    'contains the requested slug are emitted; others are suppressed.';

-- ---------------------------------------------------------------
-- 2. Insert the unified upc.apl row.
--
-- Inherits default_color from the merits row (the most-used appeal
-- track today). sort_order follows the cluster of UPC proceedings;
-- placed just before upc.apl.merits's old slot so the chip-grouped
-- picker UI lands Berufung in a sensible position. Tweakable later
-- without a migration.
-- ---------------------------------------------------------------

INSERT INTO paliad.proceeding_types (
    code, name, name_en, description, jurisdiction, category,
    default_color, sort_order, is_active, display_order,
    appeal_target
)
SELECT
    'upc.apl.unified',
    'Berufungsverfahren',
    'Appeal',
    'Vereinheitlichtes Berufungsverfahren — wählen Sie anschließend, '
    'worauf die Berufung sich richtet (Endentscheidung, '
    'Kostenentscheidung, Anordnung, Schadensbemessung, Bucheinsicht).',
    'UPC',
    'fristenrechner',
    default_color,
    sort_order,
    true,
    display_order,
    NULL
FROM paliad.proceeding_types
WHERE code = 'upc.apl.merits';

-- ---------------------------------------------------------------
-- 3. Audit-first RAISE NOTICE pass.
--
-- Lists every rule row that will be reassigned + every proceeding_type
-- row that will be archived. The migration runs to completion either
-- way; the operator reads the notices to confirm scope before the
-- next migration in the chain.
-- ---------------------------------------------------------------

DO $$
DECLARE
    rec record;
    upc_apl_id int;
    rules_touched int := 0;
    procs_archived int := 0;
BEGIN
    SELECT id INTO upc_apl_id
      FROM paliad.proceeding_types
     WHERE code = 'upc.apl.unified';
    RAISE NOTICE '[mig 134] new upc.apl.unified proceeding_type_id = %', upc_apl_id;

    RAISE NOTICE '[mig 134] Rules to reassign to upc.apl.unified with applies_to_target:';
    FOR rec IN
        SELECT dr.id AS rule_id,
               pt.code AS old_proceeding,
               dr.submission_code,
               dr.name
          FROM paliad.deadline_rules dr
          JOIN paliad.proceeding_types pt ON pt.id = dr.proceeding_type_id
         WHERE pt.code IN ('upc.apl.merits', 'upc.apl.cost', 'upc.apl.order')
           AND dr.is_active = true
        ORDER BY pt.code, dr.sequence_order
    LOOP
        RAISE NOTICE '[mig 134]   %  %  %  (%)',
            rec.old_proceeding, rec.submission_code, rec.name, rec.rule_id;
        rules_touched := rules_touched + 1;
    END LOOP;
    RAISE NOTICE '[mig 134] Total rules to reassign: %', rules_touched;

    RAISE NOTICE '[mig 134] Proceeding_types to archive (is_active=false):';
    FOR rec IN
        SELECT id, code, name
          FROM paliad.proceeding_types
         WHERE code IN ('upc.apl.merits', 'upc.apl.cost', 'upc.apl.order')
         ORDER BY sort_order
    LOOP
        RAISE NOTICE '[mig 134]   %  %  (id=%)', rec.code, rec.name, rec.id;
        procs_archived := procs_archived + 1;
    END LOOP;
    RAISE NOTICE '[mig 134] Total proceeding_types to archive: %', procs_archived;
END $$;

-- ---------------------------------------------------------------
-- 4. Reassign rule rows.
--
-- Stamp applies_to_target by source proceeding code, then point all
-- 16 rules at the new upc.apl row.
-- ---------------------------------------------------------------

-- 4a. upc.apl.merits → applies_to_target = {endentscheidung}
UPDATE paliad.deadline_rules dr
   SET applies_to_target = ARRAY['endentscheidung']::text[]
  FROM paliad.proceeding_types pt
 WHERE pt.id = dr.proceeding_type_id
   AND pt.code = 'upc.apl.merits'
   AND dr.is_active = true;

-- 4b. upc.apl.cost → applies_to_target = {kostenentscheidung}
UPDATE paliad.deadline_rules dr
   SET applies_to_target = ARRAY['kostenentscheidung']::text[]
  FROM paliad.proceeding_types pt
 WHERE pt.id = dr.proceeding_type_id
   AND pt.code = 'upc.apl.cost'
   AND dr.is_active = true;

-- 4c. upc.apl.order → applies_to_target = {anordnung}
UPDATE paliad.deadline_rules dr
   SET applies_to_target = ARRAY['anordnung']::text[]
  FROM paliad.proceeding_types pt
 WHERE pt.id = dr.proceeding_type_id
   AND pt.code = 'upc.apl.order'
   AND dr.is_active = true;

-- 4d. Reassign all 16 rules to the new upc.apl.unified proceeding_type row.
UPDATE paliad.deadline_rules dr
   SET proceeding_type_id = (
        SELECT id FROM paliad.proceeding_types WHERE code = 'upc.apl.unified'
       )
  FROM paliad.proceeding_types pt
 WHERE pt.id = dr.proceeding_type_id
   AND pt.code IN ('upc.apl.merits', 'upc.apl.cost', 'upc.apl.order');

-- ---------------------------------------------------------------
-- 5. Archive the 3 old proceeding_types.
--
-- NEVER DELETE — historical project_event_choices and project FKs
-- (paliad.projects.proceeding_type_id) may still reference these IDs.
-- The is_active=false flag stops them appearing in the picker but
-- preserves FK integrity for historical reads.
-- ---------------------------------------------------------------

UPDATE paliad.proceeding_types
   SET is_active = false
 WHERE code IN ('upc.apl.merits', 'upc.apl.cost', 'upc.apl.order');

-- ---------------------------------------------------------------
-- 6. Post-migration sanity check.
-- ---------------------------------------------------------------

DO $$
DECLARE
    unified_count int;
    archived_count int;
    target_distribution record;
BEGIN
    SELECT COUNT(*) INTO unified_count
      FROM paliad.deadline_rules dr
      JOIN paliad.proceeding_types pt ON pt.id = dr.proceeding_type_id
     WHERE pt.code = 'upc.apl.unified' AND dr.is_active = true;
    RAISE NOTICE '[mig 134] post: rules on unified upc.apl.unified = % (expected 16)', unified_count;
    IF unified_count <> 16 THEN
        RAISE EXCEPTION '[mig 134] FAILED — expected 16 rules on upc.apl.unified, got %', unified_count;
    END IF;

    SELECT COUNT(*) INTO archived_count
      FROM paliad.proceeding_types
     WHERE code IN ('upc.apl.merits', 'upc.apl.cost', 'upc.apl.order')
       AND is_active = false;
    RAISE NOTICE '[mig 134] post: archived old appeal proceeding_types = % (expected 3)', archived_count;
    IF archived_count <> 3 THEN
        RAISE EXCEPTION '[mig 134] FAILED — expected 3 archived types, got %', archived_count;
    END IF;

    FOR target_distribution IN
        SELECT unnest(applies_to_target) AS target, COUNT(*) AS n
          FROM paliad.deadline_rules dr
          JOIN paliad.proceeding_types pt ON pt.id = dr.proceeding_type_id
         WHERE pt.code = 'upc.apl.unified' AND dr.is_active = true
         GROUP BY unnest(applies_to_target)
         ORDER BY 1
    LOOP
        RAISE NOTICE '[mig 134] post: applies_to_target=%  count=%',
            target_distribution.target, target_distribution.n;
    END LOOP;
END $$;

-- ---------------------------------------------------------------
-- TODO (follow-up slice, not in 134):
--
-- Seed rules for Schadensbemessung-as-appeal + Bucheinsicht-as-appeal.
-- m's 2026-05-26 decision: distinct rule sets, NOT shared with merits.
-- - Schadensbemessung: anchor on R.118.4 decision; conjecture 2/4-month
--   merits-style track but distinct legal basis.
-- - Bucheinsicht: anchor on R.142 (Lay-open-books decision); conjecture
--   15-day track per R.220.2 + R.224.2.b.
-- Can pair with t-paliad-193 orphan-concept-seed if m wants a combined
-- editorial pass via /admin/rules.
-- ---------------------------------------------------------------
