CREATE OR REPLACE FUNCTION has_node_access(p_node_id UUID, p_user_id UUID)
RETURNS BOOLEAN
LANGUAGE sql
STABLE
AS $$
WITH RECURSIVE ancestors AS (
    SELECT id, parent_id FROM files_nodes WHERE id = p_node_id AND deleted_at IS NULL
    UNION ALL
    SELECT p.id, p.parent_id
      FROM files_nodes p
      JOIN ancestors a ON a.parent_id = p.id
     WHERE p.deleted_at IS NULL
)
SELECT EXISTS (
    SELECT 1
      FROM ancestors a
      JOIN files_access fa ON fa.node_id = a.id
     WHERE fa.user_id = p_user_id
);
$$;

CREATE OR REPLACE FUNCTION effective_node_access(p_node_id UUID, p_user_id UUID, p_subordinate_ids TEXT[])
RETURNS TEXT
LANGUAGE sql
STABLE
AS $$
WITH RECURSIVE ancestors AS (
    SELECT id, parent_id, owner_user_id FROM files_nodes WHERE id = p_node_id AND deleted_at IS NULL
    UNION ALL
    SELECT p.id, p.parent_id, p.owner_user_id
      FROM files_nodes p
      JOIN ancestors a ON a.parent_id = p.id
     WHERE p.deleted_at IS NULL
),
direct_access AS (
    SELECT fa.access_level
      FROM ancestors a
      JOIN files_access fa ON fa.node_id = a.id
     WHERE fa.user_id = p_user_id
)
SELECT CASE
    WHEN EXISTS (SELECT 1 FROM files_nodes n WHERE n.id = p_node_id AND n.owner_user_id = p_user_id AND n.deleted_at IS NULL) THEN 'edit'
    WHEN EXISTS (SELECT 1 FROM files_nodes n WHERE n.id = p_node_id AND n.owner_user_id::text = ANY(p_subordinate_ids) AND n.deleted_at IS NULL) THEN 'view'
    WHEN EXISTS (SELECT 1 FROM direct_access WHERE access_level = 'edit') THEN 'edit'
    WHEN EXISTS (SELECT 1 FROM direct_access) THEN 'view'
    ELSE ''
END;
$$;
