-- t-paliad-165: junction paliad.deadline_concept_event_types — maps each
-- deadline_concept to the canonical paliad.event_types row(s) that
-- represent it on the Typ chip cluster of the deadline create form.
--
-- Why this exists
-- ---------------
-- The deadline create form (/projects/{id}/deadlines/new and the global
-- /deadlines/new) lets the user pick a Regel (paliad.deadline_rules) AND
-- independently pick a Typ (paliad.event_types). They are decoupled, so a
-- user can save a deadline whose Regel is `damages.rejoin — Duplik` but
-- Typ is `Klageerwiderung` — two different legal events. m hit this
-- contradiction during 2026-05-08 dogfooding (Gitea m/paliad#18).
--
-- Each rule already carries paliad.deadline_rules.concept_id (mig 040),
-- so the rule knows what legal idea it represents. What was missing was
-- the canonical event_type for that concept. Slug-pattern heuristics are
-- unreliable (concept `notice-of-appeal` ↔ event_type
-- `upc_statement_of_appeal_2201`) and many concepts have multiple
-- candidate event_types (`statement-of-defence` ↔ base + with_ccr +
-- no_ccr); this junction makes the mapping explicit and curated.
--
-- Shape
-- -----
-- Many-to-many, so concepts that genuinely have several candidate types
-- (with_ccr / no_ccr / base; UPC + EPO + DPMA opposition) get one row
-- per type. is_default picks the single row the create-form auto-fills
-- when the user picks a Regel attached to this concept. The remaining
-- rows are reserved for future surfaces (e.g. Determinator save flow
-- might want to see all candidates) but the create-form only consumes
-- is_default for now.
--
-- Idempotent against re-seeds: the seed below uses ON CONFLICT DO
-- NOTHING so a second run after manual mapping additions doesn't blow
-- them away. Down migration drops the table entirely.

CREATE TABLE IF NOT EXISTS paliad.deadline_concept_event_types (
    concept_id    uuid NOT NULL
                  REFERENCES paliad.deadline_concepts(id) ON DELETE CASCADE,
    event_type_id uuid NOT NULL
                  REFERENCES paliad.event_types(id) ON DELETE CASCADE,
    is_default    bool NOT NULL DEFAULT false,
    sort_order    int  NOT NULL DEFAULT 100,
    created_at    timestamptz NOT NULL DEFAULT now(),
    PRIMARY KEY (concept_id, event_type_id)
);

COMMENT ON TABLE paliad.deadline_concept_event_types IS
    'Junction mapping paliad.deadline_concepts → paliad.event_types. '
    'Lets the deadline create form auto-populate the Typ chip when the '
    'user picks a Regel — the rule''s concept points here for its '
    'canonical event_type(s). Many-to-many for concepts with several '
    'natural variants (with_ccr / no_ccr / base, EPO + DPMA opposition).';

COMMENT ON COLUMN paliad.deadline_concept_event_types.is_default IS
    'Exactly one row per concept_id should be marked default — that is '
    'the row the create-form chip cluster auto-fills with. Other rows '
    'remain selectable from the picker as alternatives.';

CREATE UNIQUE INDEX IF NOT EXISTS deadline_concept_event_types_one_default
    ON paliad.deadline_concept_event_types (concept_id)
    WHERE is_default = true;

CREATE INDEX IF NOT EXISTS deadline_concept_event_types_event_type
    ON paliad.deadline_concept_event_types (event_type_id);

-- ============================================================================
-- Seed: curated mapping for active concepts that drive existing rules.
--
-- Concepts without an obvious event_type counterpart (filing, grant,
-- decision, publication, communication-r71-3, search-report, the various
-- DE-only Begründung concepts) stay unmapped — auto-fill silently
-- skips them, leaving the user to pick a Typ manually as today.
-- Future migrations can fill those gaps as event_types are added.
-- ============================================================================

INSERT INTO paliad.deadline_concept_event_types (concept_id, event_type_id, is_default, sort_order)
SELECT dc.id, et.id, mapping.is_default, mapping.sort_order
  FROM (VALUES
    -- (concept_slug, event_type_slug, is_default, sort_order)
    ('application-for-cost-decision',                'upc_application_for_cost_decision',     true, 10),
    ('application-for-determination-of-damages',     'upc_application_for_damages',           true, 10),
    ('application-for-revocation',                   'upc_statement_for_revocation',          true, 10),
    ('application-for-provisional-measures',         'upc_protective_letter',                 true, 10),
    ('cost-decision',                                'upc_decision_on_costs',                 true, 10),
    ('counterclaim-for-infringement',                'upc_counterclaim_for_infringement',     true, 10),
    ('counterclaim-for-revocation',                  'upc_counterclaim_for_revocation',       true, 10),
    ('cross-appeal',                                 'upc_cross_appeal_2242a',                true, 10),
    ('defence-to-application-to-amend',              'upc_defence_to_amend_patent',           true, 10),
    ('defence-to-counterclaim-for-revocation',       'upc_defence_to_revocation',             true, 10),
    ('notice-of-appeal',                             'upc_statement_of_appeal_2201',          true, 10),
    ('opposition',                                   'epo_opposition_filing',                 true, 10),
    ('opposition',                                   'dpma_opposition',                       false, 20),
    ('oral-hearing',                                 'upc_oral_hearing',                      true, 10),
    ('order',                                        'upc_case_management_order',             true, 10),
    ('rejoinder',                                    'upc_rejoinder_to_reply',                true, 10),
    ('reply-to-cross-appeal',                        'upc_cross_appeal_2242a',                true, 10),
    ('reply-to-defence',                             'upc_reply_to_defence',                  true, 10),
    ('reply-to-defence-to-application-to-amend',     'upc_reply_to_defence_to_amend_patent',  true, 10),
    ('reply-to-defence-to-counterclaim-for-revocation','upc_reply_to_defence_to_revocation',  true, 10),
    ('request-for-examination',                      'dpma_examination_request',              true, 10),
    ('request-to-lay-open-books',                    'upc_request_to_lay_open_books',         true, 10),
    ('response-to-appeal',                           'upc_grounds_of_appeal_2242a',           true, 10),
    ('statement-of-claim',                           'upc_statement_of_claim',                true, 10),
    ('statement-of-defence',                         'upc_statement_of_defence',              true, 10),
    ('statement-of-defence',                         'upc_statement_of_defence_with_ccr',     false, 20),
    ('statement-of-defence',                         'upc_statement_of_defence_no_ccr',       false, 30),
    ('statement-of-grounds-of-appeal',               'upc_grounds_of_appeal_2242a',           true, 10),
    ('statement-of-grounds-of-appeal',               'epo_appeal_grounds',                    false, 20)
  ) AS mapping(concept_slug, event_type_slug, is_default, sort_order)
  JOIN paliad.deadline_concepts dc ON dc.slug = mapping.concept_slug
  JOIN paliad.event_types et       ON et.slug = mapping.event_type_slug
                                  AND et.archived_at IS NULL
ON CONFLICT (concept_id, event_type_id) DO NOTHING;
