-- Best-effort revert of 021. NOT a clean roll-back — this migration only
-- restores the broken German-bodied versions of can_see_project /
-- note_is_visible / projekte_*; if the underlying tables have already been
-- renamed to English (i.e. 020 hasn't been rolled back yet), the German
-- bodies will still error. Run 020 / 018 down first if you really want to
-- get back to a working German state.
--
-- We do not recreate the dropped policies under their previous German names;
-- migration 018 / 020 down rebuilds the German-named policy set, and the
-- English-named policies created by 021.up are the right starting point for
-- those rollbacks.

-- ---------------------------------------------------------------------------
-- Revert trigger functions
-- ---------------------------------------------------------------------------
DROP TRIGGER  IF EXISTS projects_sync_path_before        ON paliad.projects;
DROP TRIGGER  IF EXISTS projects_rewrite_subtree_after   ON paliad.projects;
DROP FUNCTION IF EXISTS paliad.projects_sync_path()        CASCADE;
DROP FUNCTION IF EXISTS paliad.projects_rewrite_subtree()  CASCADE;

CREATE OR REPLACE FUNCTION paliad.projekte_sync_path()
RETURNS trigger
LANGUAGE plpgsql
AS $$
DECLARE
    parent_path text;
BEGIN
    IF NEW.parent_id IS NULL THEN
        NEW.path := NEW.id::text;
    ELSE
        SELECT path INTO parent_path
          FROM paliad.projekte
         WHERE id = NEW.parent_id;
        IF parent_path IS NULL THEN
            RAISE EXCEPTION 'parent projekt % not found', NEW.parent_id;
        END IF;
        IF parent_path = NEW.id::text
           OR parent_path LIKE '%.' || NEW.id::text
           OR parent_path LIKE NEW.id::text || '.%'
           OR parent_path LIKE '%.' || NEW.id::text || '.%'
        THEN
            RAISE EXCEPTION 'cannot set parent to own descendant';
        END IF;
        NEW.path := parent_path || '.' || NEW.id::text;
    END IF;
    RETURN NEW;
END;
$$;

CREATE OR REPLACE FUNCTION paliad.projekte_rewrite_subtree()
RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
    IF OLD.path IS DISTINCT FROM NEW.path THEN
        UPDATE paliad.projekte
           SET path = NEW.path || substring(path FROM length(OLD.path) + 1)
         WHERE path LIKE OLD.path || '.%';
    END IF;
    RETURN NEW;
END;
$$;

-- The triggers can only be bound to a table that exists; pick whichever of
-- paliad.projekte / paliad.projects is currently around.
DO $$ BEGIN
    EXECUTE 'CREATE TRIGGER projekte_sync_path_before BEFORE INSERT OR UPDATE OF parent_id ON paliad.projekte FOR EACH ROW EXECUTE FUNCTION paliad.projekte_sync_path()';
EXCEPTION WHEN undefined_table THEN
    EXECUTE 'CREATE TRIGGER projekte_sync_path_before BEFORE INSERT OR UPDATE OF parent_id ON paliad.projects FOR EACH ROW EXECUTE FUNCTION paliad.projekte_sync_path()';
END $$;

DO $$ BEGIN
    EXECUTE 'CREATE TRIGGER projekte_rewrite_subtree_after AFTER UPDATE OF path ON paliad.projekte FOR EACH ROW EXECUTE FUNCTION paliad.projekte_rewrite_subtree()';
EXCEPTION WHEN undefined_table THEN
    EXECUTE 'CREATE TRIGGER projekte_rewrite_subtree_after AFTER UPDATE OF path ON paliad.projects FOR EACH ROW EXECUTE FUNCTION paliad.projekte_rewrite_subtree()';
END $$;

-- ---------------------------------------------------------------------------
-- Revert visibility functions to their pre-021 (broken) state
-- ---------------------------------------------------------------------------
DROP FUNCTION IF EXISTS paliad.note_is_visible(uuid, uuid, uuid, uuid) CASCADE;
DROP FUNCTION IF EXISTS paliad.can_see_project(uuid)                   CASCADE;

CREATE FUNCTION paliad.can_see_project(_projekt_id uuid)
RETURNS boolean
LANGUAGE sql
STABLE
SECURITY DEFINER
SET search_path = paliad, public
AS $$
    SELECT EXISTS (
        SELECT 1 FROM paliad.users u
         WHERE u.id = auth.uid() AND u.role = 'admin'
    )
    OR EXISTS (
        SELECT 1
          FROM paliad.projekte      target
          JOIN paliad.projekt_teams pt
            ON pt.user_id = auth.uid()
           AND pt.projekt_id = ANY(string_to_array(target.path, '.')::uuid[])
         WHERE target.id = _projekt_id
    );
$$;

CREATE FUNCTION paliad.note_is_visible(
    _projekt_id       uuid,
    _frist_id         uuid,
    _termin_id        uuid,
    _projekt_event_id uuid
) RETURNS boolean
LANGUAGE sql
STABLE
SECURITY DEFINER
SET search_path = paliad, public
AS $$
    SELECT CASE
        WHEN _projekt_id IS NOT NULL THEN paliad.can_see_projekt(_projekt_id)
        WHEN _frist_id   IS NOT NULL THEN paliad.can_see_projekt(
            (SELECT projekt_id FROM paliad.fristen WHERE id = _frist_id))
        WHEN _termin_id  IS NOT NULL THEN
            CASE
                WHEN (SELECT projekt_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_projekt(
                    (SELECT projekt_id FROM paliad.termine WHERE id = _termin_id))
            END
        WHEN _projekt_event_id IS NOT NULL THEN paliad.can_see_projekt(
            (SELECT projekt_id FROM paliad.projekt_events WHERE id = _projekt_event_id))
        ELSE false
    END;
$$;
