-- t-paliad-088: Event Types for deadlines.
--
-- A user-facing categorization of deadlines: "what kind of work is this?"
-- (Statement of Defence, Reply, Decision on the merits, EPO opposition,
-- DPMA Beschwerde, IP licence renewal, …). Distinct from
-- paliad.trigger_events (calc-engine state, UPC-only, verbatim youpc
-- imports). The two concepts overlap by ~70% of UPC rows, so seeded
-- firm-wide types carry an OPTIONAL trigger_event_id linkage column.
-- The column has NO foreign-key constraint by design — event_types
-- leads, trigger_events follows. If a youpc re-sync drops a trigger
-- event id, the seeded event_type stays usable.
--
-- Per-deadline mapping is many-to-many via paliad.deadline_event_types.
-- A deadline can be tagged with 0..N event types.
--
-- Permissions:
--   - Any authenticated user can create both private (is_firm_wide=false)
--     and firm-wide (is_firm_wide=true) types.
--   - Authors can edit/archive their own rows.
--   - global_admin can edit/archive any firm-wide row (moderation lever).
--   - Soft-delete only (archived_at); never hard delete — existing
--     deadlines hold references to archived types and should keep their
--     label.
--
-- The Go service layer enforces visibility (firm-wide ∪ own-private)
-- because the connection runs as service-role; RLS below is
-- defense-in-depth for any auth-context query path.

-- ============================================================================
-- Schema: paliad.event_types
-- ============================================================================

CREATE TABLE paliad.event_types (
    id               uuid PRIMARY KEY DEFAULT gen_random_uuid(),
    slug             text NOT NULL,
    label_de         text NOT NULL,
    label_en         text NOT NULL,
    category         text NOT NULL DEFAULT 'submission'
                     CHECK (category IN ('submission','decision','order','service','fee','hearing','other')),
    jurisdiction     text
                     CHECK (jurisdiction IS NULL OR jurisdiction IN ('UPC','EPO','DPMA','DE','any')),
    description      text NOT NULL DEFAULT '',
    trigger_event_id bigint,
    created_by       uuid REFERENCES paliad.users(id) ON DELETE SET NULL,
    is_firm_wide     boolean NOT NULL DEFAULT false,
    archived_at      timestamptz,
    created_at       timestamptz NOT NULL DEFAULT now(),
    updated_at       timestamptz NOT NULL DEFAULT now()
);

-- Slug uniqueness: firm-wide types share one namespace; private types
-- are scoped per user so two users can each have their own "klage".
CREATE UNIQUE INDEX event_types_firm_slug_idx
    ON paliad.event_types(slug)
    WHERE is_firm_wide = true AND archived_at IS NULL;

CREATE UNIQUE INDEX event_types_private_slug_idx
    ON paliad.event_types(created_by, slug)
    WHERE is_firm_wide = false AND archived_at IS NULL;

CREATE INDEX event_types_category_idx     ON paliad.event_types(category);
CREATE INDEX event_types_jurisdiction_idx ON paliad.event_types(jurisdiction) WHERE jurisdiction IS NOT NULL;
CREATE INDEX event_types_trigger_event_idx ON paliad.event_types(trigger_event_id) WHERE trigger_event_id IS NOT NULL;

-- ============================================================================
-- Schema: paliad.deadline_event_types (junction)
-- ============================================================================

CREATE TABLE paliad.deadline_event_types (
    deadline_id    uuid NOT NULL REFERENCES paliad.deadlines(id)    ON DELETE CASCADE,
    event_type_id  uuid NOT NULL REFERENCES paliad.event_types(id)  ON DELETE CASCADE,
    created_at     timestamptz NOT NULL DEFAULT now(),
    PRIMARY KEY (deadline_id, event_type_id)
);

-- PK index covers WHERE deadline_id = ?; need a separate one for the
-- reverse direction (filter list by event_type_id).
CREATE INDEX deadline_event_types_event_type_idx
    ON paliad.deadline_event_types(event_type_id);

-- ============================================================================
-- RLS (defense-in-depth; primary enforcement is in the Go service)
-- ============================================================================

ALTER TABLE paliad.event_types          ENABLE ROW LEVEL SECURITY;
ALTER TABLE paliad.deadline_event_types ENABLE ROW LEVEL SECURITY;

-- event_types: read firm-wide ∪ own private. Insert any row with
-- created_by=self. Update own rows; admins update any firm-wide row.
CREATE POLICY event_types_select ON paliad.event_types
    FOR SELECT TO authenticated
    USING (
        archived_at IS NULL
        AND (is_firm_wide = true OR created_by = auth.uid())
    );

CREATE POLICY event_types_insert ON paliad.event_types
    FOR INSERT TO authenticated
    WITH CHECK (created_by = auth.uid());

CREATE POLICY event_types_update_owner ON paliad.event_types
    FOR UPDATE TO authenticated
    USING (created_by = auth.uid())
    WITH CHECK (created_by = auth.uid());

CREATE POLICY event_types_update_admin ON paliad.event_types
    FOR UPDATE TO authenticated
    USING (
        is_firm_wide = true
        AND EXISTS (
            SELECT 1 FROM paliad.users u
            WHERE u.id = auth.uid() AND u.global_role = 'global_admin'
        )
    );

-- deadline_event_types: visibility follows the parent Deadline's
-- Project visibility (paliad.can_see_project), AND the event_type itself
-- must be visible to the user.
CREATE POLICY deadline_event_types_all ON paliad.deadline_event_types
    FOR ALL TO authenticated
    USING (
        EXISTS (
            SELECT 1 FROM paliad.deadlines d
            WHERE d.id = deadline_event_types.deadline_id
              AND paliad.can_see_project(d.project_id)
        )
        AND EXISTS (
            SELECT 1 FROM paliad.event_types et
            WHERE et.id = deadline_event_types.event_type_id
              AND et.archived_at IS NULL
              AND (et.is_firm_wide = true OR et.created_by = auth.uid())
        )
    )
    WITH CHECK (
        EXISTS (
            SELECT 1 FROM paliad.deadlines d
            WHERE d.id = deadline_event_types.deadline_id
              AND paliad.can_see_project(d.project_id)
        )
        AND EXISTS (
            SELECT 1 FROM paliad.event_types et
            WHERE et.id = deadline_event_types.event_type_id
              AND et.archived_at IS NULL
              AND (et.is_firm_wide = true OR et.created_by = auth.uid())
        )
    );

-- ============================================================================
-- Seed: ~40 firm-wide types, biased toward submissions per m's Q3 call.
-- created_by = NULL marks them as system seeds (no human author).
-- trigger_event_id linkage populated only for seeded UPC rows.
-- ============================================================================

INSERT INTO paliad.event_types
    (slug, label_de, label_en, category, jurisdiction, description, trigger_event_id, is_firm_wide)
VALUES
    -- UPC submissions (25 rows)
    ('upc_statement_of_claim',                     'Klageschrift',                                          'Statement of Claim',                                                  'submission', 'UPC', '',                                                                  5,   true),
    ('upc_statement_of_defence',                   'Klageerwiderung',                                       'Statement of Defence',                                                'submission', 'UPC', '',                                                                  84,  true),
    ('upc_statement_of_defence_with_ccr',          'Klageerwiderung mit Widerklage auf Nichtigerklärung',   'Statement of Defence with Counterclaim for Revocation',              'submission', 'UPC', '',                                                                  1,   true),
    ('upc_statement_of_defence_no_ccr',            'Klageerwiderung ohne Widerklage auf Nichtigerklärung',  'Statement of Defence without Counterclaim for Revocation',           'submission', 'UPC', '',                                                                  28,  true),
    ('upc_reply_to_defence',                       'Replik',                                                'Reply to the Statement of Defence',                                  'submission', 'UPC', '',                                                                  85,  true),
    ('upc_rejoinder_to_reply',                     'Duplik',                                                'Rejoinder to the Reply to the Statement of Defence',                 'submission', 'UPC', '',                                                                  61,  true),
    ('upc_counterclaim_for_revocation',            'Widerklage auf Nichtigerklärung',                       'Counterclaim for Revocation',                                         'submission', 'UPC', '',                                                                  101, true),
    ('upc_counterclaim_for_infringement',          'Widerklage wegen Verletzung',                           'Counterclaim for Infringement',                                       'submission', 'UPC', '',                                                                  10,  true),
    ('upc_defence_to_revocation',                  'Erwiderung auf Nichtigkeitsantrag',                     'Defence to revocation',                                               'submission', 'UPC', '',                                                                  34,  true),
    ('upc_reply_to_defence_to_revocation',         'Replik auf Erwiderung auf Nichtigkeitsantrag',          'Reply to the Defence to revocation',                                  'submission', 'UPC', '',                                                                  21,  true),
    ('upc_application_to_amend_patent',            'Antrag auf Patentänderung',                             'Application to amend the patent',                                     'submission', 'UPC', '',                                                                  38,  true),
    ('upc_defence_to_amend_patent',                'Erwiderung auf Patentänderungsantrag',                  'Defence to the Application to amend the patent',                      'submission', 'UPC', '',                                                                  19,  true),
    ('upc_reply_to_defence_to_amend_patent',       'Replik auf Erwiderung auf Patentänderungsantrag',       'Reply to the Defence to an Application to amend the patent',          'submission', 'UPC', '',                                                                  20,  true),
    ('upc_statement_for_revocation',               'Nichtigkeitsklage',                                     'Statement for Revocation',                                            'submission', 'UPC', '',                                                                  6,   true),
    ('upc_statement_dni',                          'Antrag auf Feststellung der Nichtverletzung',           'Statement for a declaration of non-infringement',                     'submission', 'UPC', '',                                                                  7,   true),
    ('upc_defence_to_statement_dni',               'Erwiderung auf Antrag auf Feststellung der Nichtverletzung', 'Defence to the Statement for a declaration of non-infringement', 'submission', 'UPC', '',                                                                  93,  true),
    ('upc_application_for_cost_decision',          'Antrag auf Kostenentscheidung',                         'Application for cost decision',                                       'submission', 'UPC', '',                                                                  8,   true),
    ('upc_statement_of_appeal_2201',               'Berufungsschrift (R.220.1(a)/(b))',                     'Statement of Appeal against decision Rule 220.1(a)/(b)',              'submission', 'UPC', '',                                                                  11,  true),
    ('upc_grounds_of_appeal_2242a',                'Berufungsbegründung (R.224.2(a))',                      'Statement of grounds of appeal pursuant to Rule 224.2(a)',            'submission', 'UPC', '',                                                                  89,  true),
    ('upc_grounds_of_appeal_2242b',                'Berufungsbegründung (R.224.2(b))',                      'Statement of grounds of appeal pursuant to Rule 224.2(b)',            'submission', 'UPC', '',                                                                  60,  true),
    ('upc_cross_appeal_2242a',                     'Anschlussberufung (R.224.2(a))',                        'Statement of cross-appeal pursuant to Rule 224.2(a)',                 'submission', 'UPC', '',                                                                  63,  true),
    ('upc_application_for_damages',                'Antrag auf Schadensbestimmung',                         'Application for the determination of damages',                        'submission', 'UPC', '',                                                                  82,  true),
    ('upc_protective_letter',                      'Schutzschrift',                                         'Protective Letter',                                                   'submission', 'UPC', '',                                                                  55,  true),
    ('upc_preliminary_objection',                  'Vorbringen zur Unzulässigkeit',                         'Preliminary Objection',                                               'submission', 'UPC', '',                                                                  68,  true),
    ('upc_request_to_lay_open_books',              'Antrag auf Buchoffenlegung',                            'Request to lay open books',                                           'submission', 'UPC', '',                                                                  62,  true),

    -- UPC decisions / orders / hearings (8 rows)
    ('upc_decision_on_merits',                     'Hauptsacheentscheidung',                                'Decision on the merits',                                              'decision',   'UPC', '',                                                                  104, true),
    ('upc_decision_on_costs',                      'Kostenfestsetzungsbeschluss (R.157)',                   'Decision on fixation of costs (Rule 157)',                            'decision',   'UPC', '',                                                                  2,   true),
    ('upc_decision_of_epo',                        'Entscheidung des EPA',                                  'Decision of the EPO',                                                 'decision',   'UPC', '',                                                                  39,  true),
    ('upc_case_management_order',                  'Verfahrensleitende Anordnung (Zustellung)',             'Case management order (Service)',                                     'order',      'UPC', '',                                                                  78,  true),
    ('upc_order_lodge_translations',               'Anordnung Übersetzungseinreichung',                     'Order of the judge-rapporteur to lodge translations',                 'order',      'UPC', '',                                                                  113, true),
    ('upc_summons_oral_hearing',                   'Ladung zur mündlichen Verhandlung',                     'Summons to Oral Hearing',                                             'service',    'UPC', '',                                                                  56,  true),
    ('upc_oral_hearing',                           'Mündliche Verhandlung',                                 'Oral hearing',                                                        'hearing',    'UPC', '',                                                                  49,  true),
    ('upc_final_decision',                         'Endurteil (Zustellung)',                                'Final decision (Service)',                                            'decision',   'UPC', '',                                                                  88,  true),

    -- EPO (4 rows, no trigger_event_id — out of UPC corpus)
    ('epo_opposition_filing',                      'Einspruch gegen EP-Patent',                             'Notice of Opposition (EPO)',                                          'submission', 'EPO', 'Article 99 EPC, 9-month opposition period',                          NULL, true),
    ('epo_opposition_reply',                       'Erwiderung im Einspruchsverfahren (EPA)',               'Reply in EPO opposition proceedings',                                 'submission', 'EPO', '',                                                                  NULL, true),
    ('epo_appeal_notice',                          'Beschwerdeschrift (EPA)',                               'Notice of Appeal (EPO)',                                              'submission', 'EPO', 'Article 108 EPC, 2-month notice + 4-month grounds',                 NULL, true),
    ('epo_appeal_grounds',                         'Beschwerdebegründung (EPA)',                            'Statement of Grounds of Appeal (EPO)',                                'submission', 'EPO', '',                                                                  NULL, true),
    ('epo_renewal_fee',                            'Jahresgebühr (EP)',                                     'Renewal fee (EP)',                                                    'fee',        'EPO', '',                                                                  NULL, true),

    -- DPMA / DE national (4 rows, no trigger_event_id)
    ('dpma_examination_request',                   'Prüfungsantrag (DPMA)',                                 'Request for examination (DPMA)',                                      'submission', 'DPMA', '',                                                                 NULL, true),
    ('dpma_opposition',                            'Einspruch (DPMA)',                                      'Opposition (DPMA)',                                                   'submission', 'DPMA', '',                                                                 NULL, true),
    ('dpma_appeal',                                'Beschwerde (DPMA)',                                     'Appeal (DPMA)',                                                       'submission', 'DPMA', '',                                                                 NULL, true),
    ('de_klageerwiderung',                         'Klageerwiderung (DE Zivilgericht)',                     'Statement of Defence (DE national court)',                            'submission', 'DE', '',                                                                   NULL, true),

    -- Cross-jurisdiction / contract (1 row)
    ('contract_renewal',                           'Vertragsverlängerung / Lizenzerneuerung',               'Contract renewal / licence renewal',                                  'fee',        'any', 'Generic non-procedural deadline (licence renewal, NDA expiry, …)',  NULL, true);
