-- Rollback for 018_projects_v2.
--
-- Recreates paliad.akten (same UUIDs), restores akte_id FK columns on the
-- children, renames child tables back to German (notes→notizen, deadlines→
-- fristen, appointments→termine, parties→parteien, documents→dokumente,
-- project_events→akten_events), drops the new projects/team/department
-- tables. Best-effort:
--   * Child rows whose project_id points at a non-akten project row (i.e.,
--     anything created post-migration under non-'case' types) will fail
--     FK re-creation. The rollback aborts in that case — this is intentional,
--     since v2-only data has no v1 home.
--   * project_teams memberships are folded back into akten.collaborators
--     (dedup, drop role metadata); users who were only 'lead' end up in
--     the array like everyone else.
--   * owning_office is set to the creator's user.office when available,
--     else 'munich' as a last-resort fallback (documented loss).

-- 1. Recreate paliad.akten with the old shape.
CREATE TABLE paliad.akten (
    id                   uuid PRIMARY KEY,
    aktenzeichen         text NOT NULL,
    title                text NOT NULL,
    akte_type            text,
    court                text,
    court_ref            text,
    status               text NOT NULL DEFAULT 'active'
                         CHECK (status IN ('active', 'pending', 'closed', 'archived')),
    ai_summary           text,
    owning_office        text NOT NULL CHECK (owning_office IN (
                            'munich', 'duesseldorf', 'hamburg',
                            'amsterdam', 'london', 'paris', 'milan'
                         )),
    collaborators        uuid[] NOT NULL DEFAULT '{}',
    firm_wide_visible    boolean NOT NULL DEFAULT false,
    created_by           uuid REFERENCES auth.users(id) ON DELETE SET NULL,
    metadata             jsonb NOT NULL DEFAULT '{}',
    created_at           timestamptz NOT NULL DEFAULT now(),
    updated_at           timestamptz NOT NULL DEFAULT now()
);

CREATE INDEX akten_status_owning_office_idx ON paliad.akten (status, owning_office);
CREATE INDEX akten_owning_office_idx        ON paliad.akten (owning_office);
CREATE INDEX akten_firm_wide_idx            ON paliad.akten (firm_wide_visible) WHERE firm_wide_visible = true;
CREATE INDEX akten_collaborators_gin_idx    ON paliad.akten USING GIN (collaborators);

-- 2. Backfill from projects (only type='case' — others have no v1 home).
INSERT INTO paliad.akten (
    id, aktenzeichen, title, akte_type, court, court_ref, status, ai_summary,
    owning_office, collaborators, firm_wide_visible,
    created_by, metadata, created_at, updated_at
)
SELECT
    p.id,
    COALESCE(p.reference, p.id::text),
    p.title,
    NULL,
    p.court,
    p.case_number,
    CASE WHEN p.status IN ('active','pending','closed','archived')
         THEN p.status ELSE 'active' END,
    p.ai_summary,
    COALESCE(
        (SELECT u.office FROM paliad.users u WHERE u.id = p.created_by),
        'munich'
    ),
    COALESCE(
        (SELECT array_agg(DISTINCT pt.user_id)
           FROM paliad.project_teams pt
          WHERE pt.project_id = p.id
            AND pt.user_id IS NOT NULL),
        '{}'::uuid[]
    ),
    false,
    p.created_by,
    p.metadata,
    p.created_at,
    p.updated_at
  FROM paliad.projects p
 WHERE p.type = 'case';

-- 3. Drop new RLS policies + helpers we installed in .up.
DROP POLICY IF EXISTS parties_all                ON paliad.parties;
DROP POLICY IF EXISTS deadlines_all              ON paliad.deadlines;
DROP POLICY IF EXISTS appointments_select        ON paliad.appointments;
DROP POLICY IF EXISTS appointments_insert        ON paliad.appointments;
DROP POLICY IF EXISTS appointments_update        ON paliad.appointments;
DROP POLICY IF EXISTS appointments_delete        ON paliad.appointments;
DROP POLICY IF EXISTS documents_all              ON paliad.documents;
DROP POLICY IF EXISTS project_events_all         ON paliad.project_events;
DROP POLICY IF EXISTS notes_all                  ON paliad.notes;
DROP POLICY IF EXISTS checklist_instances_select ON paliad.checklist_instances;
DROP POLICY IF EXISTS checklist_instances_insert ON paliad.checklist_instances;
DROP POLICY IF EXISTS checklist_instances_update ON paliad.checklist_instances;
DROP POLICY IF EXISTS checklist_instances_delete ON paliad.checklist_instances;
DROP POLICY IF EXISTS projects_select            ON paliad.projects;
DROP POLICY IF EXISTS projects_insert            ON paliad.projects;
DROP POLICY IF EXISTS projects_update            ON paliad.projects;
DROP POLICY IF EXISTS projects_delete            ON paliad.projects;
DROP POLICY IF EXISTS project_teams_select       ON paliad.project_teams;
DROP POLICY IF EXISTS project_teams_insert       ON paliad.project_teams;
DROP POLICY IF EXISTS project_teams_update       ON paliad.project_teams;
DROP POLICY IF EXISTS project_teams_delete       ON paliad.project_teams;
DROP POLICY IF EXISTS departments_select         ON paliad.departments;
DROP POLICY IF EXISTS departments_write          ON paliad.departments;
DROP POLICY IF EXISTS department_members_select  ON paliad.department_members;
DROP POLICY IF EXISTS department_members_write   ON paliad.department_members;

DROP FUNCTION IF EXISTS paliad.note_is_visible(uuid, uuid, uuid, uuid);
DROP FUNCTION IF EXISTS paliad.can_see_project(uuid);

-- 4. Rename child tables back to German + restore akte_id column.
ALTER TABLE paliad.parties DROP CONSTRAINT IF EXISTS parties_project_id_fkey;
ALTER TABLE paliad.parties RENAME COLUMN project_id TO akte_id;
ALTER TABLE paliad.parties RENAME TO parteien;
ALTER TABLE paliad.parteien
    ADD CONSTRAINT parteien_akte_id_fkey FOREIGN KEY (akte_id)
        REFERENCES paliad.akten(id) ON DELETE CASCADE;
DROP INDEX IF EXISTS paliad.parties_project_idx;
CREATE INDEX parteien_akte_idx ON paliad.parteien (akte_id);

ALTER TABLE paliad.deadlines DROP CONSTRAINT IF EXISTS deadlines_project_id_fkey;
ALTER TABLE paliad.deadlines RENAME COLUMN project_id TO akte_id;
ALTER TABLE paliad.deadlines RENAME TO fristen;
ALTER TABLE paliad.fristen
    ADD CONSTRAINT fristen_akte_id_fkey FOREIGN KEY (akte_id)
        REFERENCES paliad.akten(id) ON DELETE CASCADE;
DROP INDEX IF EXISTS paliad.deadlines_project_idx;
DROP INDEX IF EXISTS paliad.deadlines_status_due_date_idx;
DROP INDEX IF EXISTS paliad.deadlines_due_date_idx;
CREATE INDEX fristen_akte_idx            ON paliad.fristen (akte_id);
CREATE INDEX fristen_status_due_date_idx ON paliad.fristen (status, due_date);
CREATE INDEX fristen_due_date_idx        ON paliad.fristen (due_date);

ALTER TABLE paliad.appointments DROP CONSTRAINT IF EXISTS appointments_project_id_fkey;
ALTER TABLE paliad.appointments DROP CONSTRAINT IF EXISTS appointments_appointment_type_check;
ALTER TABLE paliad.appointments RENAME COLUMN project_id       TO akte_id;
ALTER TABLE paliad.appointments RENAME COLUMN appointment_type TO termin_type;
ALTER TABLE paliad.appointments RENAME TO termine;
ALTER TABLE paliad.termine
    ADD CONSTRAINT termine_akte_id_fkey FOREIGN KEY (akte_id)
        REFERENCES paliad.akten(id) ON DELETE CASCADE,
    ADD CONSTRAINT termine_termin_type_check
        CHECK (termin_type IS NULL OR termin_type IN (
            'hearing', 'meeting', 'consultation', 'deadline_hearing'
        ));
DROP INDEX IF EXISTS paliad.appointments_project_idx;
DROP INDEX IF EXISTS paliad.appointments_start_at_idx;
CREATE INDEX termine_akte_idx     ON paliad.termine (akte_id);
CREATE INDEX termine_start_at_idx ON paliad.termine (start_at);

ALTER TABLE paliad.documents DROP CONSTRAINT IF EXISTS documents_project_id_fkey;
ALTER TABLE paliad.documents RENAME COLUMN project_id TO akte_id;
ALTER TABLE paliad.documents RENAME TO dokumente;
ALTER TABLE paliad.dokumente
    ADD CONSTRAINT dokumente_akte_id_fkey FOREIGN KEY (akte_id)
        REFERENCES paliad.akten(id) ON DELETE CASCADE;
DROP INDEX IF EXISTS paliad.documents_project_idx;
CREATE INDEX dokumente_akte_idx ON paliad.dokumente (akte_id);

ALTER TABLE paliad.project_events DROP CONSTRAINT IF EXISTS project_events_project_id_fkey;
ALTER TABLE paliad.project_events RENAME COLUMN project_id TO akte_id;
ALTER TABLE paliad.project_events RENAME TO akten_events;
ALTER TABLE paliad.akten_events
    ADD CONSTRAINT akten_events_akte_id_fkey FOREIGN KEY (akte_id)
        REFERENCES paliad.akten(id) ON DELETE CASCADE;
DROP INDEX IF EXISTS paliad.project_events_project_created_idx;
CREATE INDEX akten_events_akte_created_idx ON paliad.akten_events (akte_id, created_at DESC);

-- notes → notizen
ALTER TABLE paliad.notes DROP CONSTRAINT IF EXISTS notes_exactly_one_parent;
ALTER TABLE paliad.notes DROP CONSTRAINT IF EXISTS notes_project_id_fkey;
ALTER TABLE paliad.notes DROP CONSTRAINT IF EXISTS notes_deadline_id_fkey;
ALTER TABLE paliad.notes DROP CONSTRAINT IF EXISTS notes_appointment_id_fkey;
ALTER TABLE paliad.notes DROP CONSTRAINT IF EXISTS notes_project_event_id_fkey;
ALTER TABLE paliad.notes RENAME COLUMN project_id       TO akte_id;
ALTER TABLE paliad.notes RENAME COLUMN deadline_id      TO frist_id;
ALTER TABLE paliad.notes RENAME COLUMN appointment_id   TO termin_id;
ALTER TABLE paliad.notes RENAME COLUMN project_event_id TO akten_event_id;
ALTER TABLE paliad.notes RENAME TO notizen;
ALTER TABLE paliad.notizen
    ADD CONSTRAINT notizen_akte_id_fkey FOREIGN KEY (akte_id)
        REFERENCES paliad.akten(id) ON DELETE CASCADE,
    ADD CONSTRAINT notizen_frist_id_fkey FOREIGN KEY (frist_id)
        REFERENCES paliad.fristen(id) ON DELETE CASCADE,
    ADD CONSTRAINT notizen_termin_id_fkey FOREIGN KEY (termin_id)
        REFERENCES paliad.termine(id) ON DELETE CASCADE,
    ADD CONSTRAINT notizen_akten_event_id_fkey FOREIGN KEY (akten_event_id)
        REFERENCES paliad.akten_events(id) ON DELETE CASCADE,
    ADD CONSTRAINT notizen_exactly_one_parent CHECK (
        (CASE WHEN akte_id        IS NOT NULL THEN 1 ELSE 0 END) +
        (CASE WHEN frist_id       IS NOT NULL THEN 1 ELSE 0 END) +
        (CASE WHEN termin_id      IS NOT NULL THEN 1 ELSE 0 END) +
        (CASE WHEN akten_event_id IS NOT NULL THEN 1 ELSE 0 END) = 1
    );
DROP INDEX IF EXISTS paliad.notes_project_idx;
DROP INDEX IF EXISTS paliad.notes_deadline_idx;
DROP INDEX IF EXISTS paliad.notes_appointment_idx;
DROP INDEX IF EXISTS paliad.notes_project_event_idx;
CREATE INDEX notizen_akte_idx        ON paliad.notizen (akte_id)        WHERE akte_id        IS NOT NULL;
CREATE INDEX notizen_frist_idx       ON paliad.notizen (frist_id)       WHERE frist_id       IS NOT NULL;
CREATE INDEX notizen_termin_idx      ON paliad.notizen (termin_id)      WHERE termin_id      IS NOT NULL;
CREATE INDEX notizen_akten_event_idx ON paliad.notizen (akten_event_id) WHERE akten_event_id IS NOT NULL;

-- checklist_instances: restore akte_id column.
ALTER TABLE paliad.checklist_instances DROP CONSTRAINT IF EXISTS checklist_instances_project_id_fkey;
ALTER TABLE paliad.checklist_instances RENAME COLUMN project_id TO akte_id;
ALTER TABLE paliad.checklist_instances
    ADD CONSTRAINT checklist_instances_akte_id_fkey FOREIGN KEY (akte_id)
        REFERENCES paliad.akten(id) ON DELETE SET NULL;
DROP INDEX IF EXISTS paliad.checklist_instances_project_idx;
CREATE INDEX checklist_instances_akte_idx ON paliad.checklist_instances (akte_id) WHERE akte_id IS NOT NULL;

-- 5. Drop new tables + triggers.
DROP TRIGGER IF EXISTS projects_rewrite_subtree_after ON paliad.projects;
DROP TRIGGER IF EXISTS projects_sync_path_before      ON paliad.projects;
DROP FUNCTION IF EXISTS paliad.projects_rewrite_subtree();
DROP FUNCTION IF EXISTS paliad.projects_sync_path();

DROP TABLE IF EXISTS paliad.department_members;
DROP TABLE IF EXISTS paliad.departments;
DROP TABLE IF EXISTS paliad.project_teams;
DROP TABLE IF EXISTS paliad.projects;

-- 6. Restore the v1 visibility helpers + RLS policies.
CREATE OR REPLACE FUNCTION paliad.can_see_akte(_akte_id uuid)
RETURNS boolean
LANGUAGE sql
STABLE
SECURITY DEFINER
SET search_path = paliad, public
AS $$
    SELECT EXISTS (
        SELECT 1
        FROM paliad.akten a
        LEFT JOIN paliad.users u ON u.id = auth.uid()
        WHERE a.id = _akte_id
          AND (
               a.firm_wide_visible
            OR (u.office IS NOT NULL AND a.owning_office = u.office)
            OR auth.uid() = ANY (a.collaborators)
            OR (u.role = 'admin')
          )
    );
$$;

CREATE OR REPLACE FUNCTION paliad.notiz_is_visible(
    _akte_id         uuid,
    _frist_id        uuid,
    _termin_id       uuid,
    _akten_event_id  uuid
) RETURNS boolean
LANGUAGE sql
STABLE
SECURITY DEFINER
SET search_path = paliad, public
AS $$
    SELECT CASE
        WHEN _akte_id        IS NOT NULL THEN paliad.can_see_akte(_akte_id)
        WHEN _frist_id       IS NOT NULL THEN paliad.can_see_akte((SELECT akte_id FROM paliad.fristen      WHERE id = _frist_id))
        WHEN _termin_id      IS NOT NULL THEN
            CASE
                WHEN (SELECT akte_id FROM paliad.termine WHERE id = _termin_id) IS NULL
                    THEN (SELECT created_by FROM paliad.termine WHERE id = _termin_id) = auth.uid()
                ELSE paliad.can_see_akte((SELECT akte_id FROM paliad.termine WHERE id = _termin_id))
            END
        WHEN _akten_event_id IS NOT NULL THEN paliad.can_see_akte((SELECT akte_id FROM paliad.akten_events WHERE id = _akten_event_id))
        ELSE false
    END;
$$;

ALTER TABLE paliad.akten ENABLE ROW LEVEL SECURITY;

CREATE POLICY akten_select ON paliad.akten
    FOR SELECT TO authenticated
    USING (paliad.can_see_akte(id));

CREATE POLICY akten_insert ON paliad.akten
    FOR INSERT TO authenticated
    WITH CHECK (
        owning_office = (SELECT office FROM paliad.users WHERE id = auth.uid())
        OR (SELECT role FROM paliad.users WHERE id = auth.uid()) = 'admin'
    );

CREATE POLICY akten_update ON paliad.akten
    FOR UPDATE TO authenticated
    USING (paliad.can_see_akte(id))
    WITH CHECK (paliad.can_see_akte(id));

CREATE POLICY akten_delete ON paliad.akten
    FOR DELETE TO authenticated
    USING (
        paliad.can_see_akte(id)
        AND (SELECT role FROM paliad.users WHERE id = auth.uid()) IN ('partner', 'admin')
    );

CREATE POLICY parteien_all ON paliad.parteien
    FOR ALL TO authenticated
    USING (paliad.can_see_akte(akte_id))
    WITH CHECK (paliad.can_see_akte(akte_id));

CREATE POLICY fristen_all ON paliad.fristen
    FOR ALL TO authenticated
    USING (paliad.can_see_akte(akte_id))
    WITH CHECK (paliad.can_see_akte(akte_id));

CREATE POLICY termine_select ON paliad.termine
    FOR SELECT TO authenticated
    USING ((akte_id IS NULL AND created_by = auth.uid())
        OR (akte_id IS NOT NULL AND paliad.can_see_akte(akte_id)));
CREATE POLICY termine_insert ON paliad.termine
    FOR INSERT TO authenticated
    WITH CHECK ((akte_id IS NULL AND created_by = auth.uid())
            OR (akte_id IS NOT NULL AND paliad.can_see_akte(akte_id)));
CREATE POLICY termine_update ON paliad.termine
    FOR UPDATE TO authenticated
    USING ((akte_id IS NULL AND created_by = auth.uid())
        OR (akte_id IS NOT NULL AND paliad.can_see_akte(akte_id)))
    WITH CHECK ((akte_id IS NULL AND created_by = auth.uid())
            OR (akte_id IS NOT NULL AND paliad.can_see_akte(akte_id)));
CREATE POLICY termine_delete ON paliad.termine
    FOR DELETE TO authenticated
    USING ((akte_id IS NULL AND created_by = auth.uid())
        OR (akte_id IS NOT NULL AND paliad.can_see_akte(akte_id)));

CREATE POLICY dokumente_all ON paliad.dokumente
    FOR ALL TO authenticated
    USING (paliad.can_see_akte(akte_id))
    WITH CHECK (paliad.can_see_akte(akte_id));

CREATE POLICY akten_events_all ON paliad.akten_events
    FOR ALL TO authenticated
    USING (paliad.can_see_akte(akte_id))
    WITH CHECK (paliad.can_see_akte(akte_id));

CREATE POLICY notizen_all ON paliad.notizen
    FOR ALL TO authenticated
    USING (paliad.notiz_is_visible(akte_id, frist_id, termin_id, akten_event_id))
    WITH CHECK (paliad.notiz_is_visible(akte_id, frist_id, termin_id, akten_event_id));

CREATE POLICY checklist_instances_select ON paliad.checklist_instances
    FOR SELECT TO authenticated
    USING ((akte_id IS NULL AND created_by = auth.uid())
        OR (akte_id IS NOT NULL AND paliad.can_see_akte(akte_id)));
CREATE POLICY checklist_instances_insert ON paliad.checklist_instances
    FOR INSERT TO authenticated
    WITH CHECK (created_by = auth.uid()
             AND (akte_id IS NULL OR paliad.can_see_akte(akte_id)));
CREATE POLICY checklist_instances_update ON paliad.checklist_instances
    FOR UPDATE TO authenticated
    USING ((akte_id IS NULL AND created_by = auth.uid())
        OR (akte_id IS NOT NULL AND paliad.can_see_akte(akte_id)))
    WITH CHECK ((akte_id IS NULL AND created_by = auth.uid())
             OR (akte_id IS NOT NULL AND paliad.can_see_akte(akte_id)));
CREATE POLICY checklist_instances_delete ON paliad.checklist_instances
    FOR DELETE TO authenticated
    USING ((akte_id IS NULL AND created_by = auth.uid())
        OR (akte_id IS NOT NULL AND paliad.can_see_akte(akte_id)));

-- 7. Drop the users.additional_offices column we added.
ALTER TABLE paliad.users DROP COLUMN IF EXISTS additional_offices;
