-- Phase A: Row-Level Security policies (design §2).
--
-- Posture:
--   - users            : authenticated users can SELECT everyone; UPDATE only self; no public INSERT (Phase D handler inserts via service role)
--   - akten            : office-scoped visibility via paliad.can_see_akte()
--   - akten children   : inherit visibility via paliad.can_see_akte(akte_id)
--   - reference tables : any authenticated user can SELECT
--   - notizen          : visibility follows whichever parent is set
--
-- Every table has RLS enabled. No permissive `USING (true)` on user data.

-- ============================================================================
-- users
-- ============================================================================
ALTER TABLE paliad.users ENABLE ROW LEVEL SECURITY;

CREATE POLICY users_select_all ON paliad.users
    FOR SELECT TO authenticated
    USING (true);

CREATE POLICY users_update_self ON paliad.users
    FOR UPDATE TO authenticated
    USING (id = auth.uid())
    WITH CHECK (id = auth.uid());

CREATE POLICY users_insert_self ON paliad.users
    FOR INSERT TO authenticated
    WITH CHECK (id = auth.uid());

-- ============================================================================
-- akten
-- ============================================================================
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: user can only create Akten in their own office; admins anywhere.
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'
    );

-- Update: any user with visibility can update.
CREATE POLICY akten_update ON paliad.akten
    FOR UPDATE TO authenticated
    USING (paliad.can_see_akte(id))
    WITH CHECK (paliad.can_see_akte(id));

-- Delete: only partners and admins. (Role check redundant-safe.)
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')
    );

-- ============================================================================
-- parteien / fristen / termine / dokumente / akten_events
-- Visibility inherited from the parent Akte.
-- ============================================================================
ALTER TABLE paliad.parteien       ENABLE ROW LEVEL SECURITY;
ALTER TABLE paliad.fristen        ENABLE ROW LEVEL SECURITY;
ALTER TABLE paliad.termine        ENABLE ROW LEVEL SECURITY;
ALTER TABLE paliad.dokumente      ENABLE ROW LEVEL SECURITY;
ALTER TABLE paliad.akten_events   ENABLE ROW LEVEL SECURITY;

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));

-- termine.akte_id is nullable (personal appointments not tied to an Akte).
-- Personal appointments visible only to the creator; Akte-linked ones follow
-- the visibility predicate.
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));

-- ============================================================================
-- notizen — visibility follows whichever parent FK is set
-- ============================================================================
ALTER TABLE paliad.notizen ENABLE ROW LEVEL SECURITY;

-- Helper: notiz is visible iff its parent is visible.
-- For frist/termin/akten_event, we resolve to the underlying Akte.
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;
$$;

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));

-- ============================================================================
-- reference tables — any authenticated user can SELECT; nobody writes via API
-- ============================================================================
ALTER TABLE paliad.proceeding_types  ENABLE ROW LEVEL SECURITY;
ALTER TABLE paliad.deadline_rules    ENABLE ROW LEVEL SECURITY;
ALTER TABLE paliad.holidays          ENABLE ROW LEVEL SECURITY;

CREATE POLICY proceeding_types_select  ON paliad.proceeding_types FOR SELECT TO authenticated USING (true);
CREATE POLICY deadline_rules_select    ON paliad.deadline_rules   FOR SELECT TO authenticated USING (true);
CREATE POLICY holidays_select          ON paliad.holidays         FOR SELECT TO authenticated USING (true);
