/*
 * -------------------------------------------------------
 * Hierarchy-Aware Role & Permission Functions + RLS Policies
 *
 * Extends the flat has_role_on_account model to support
 * Verband → Subverein → Verein hierarchy.
 *
 * Design decisions:
 *   - Parents can READ children (top-down visibility)
 *   - Children CANNOT see parents or siblings
 *   - Writes remain strictly per-account (no cascade)
 *   - Only team accounts participate in hierarchy
 * -------------------------------------------------------
 */

-- -------------------------------------------------------
-- Core: check role on account OR any ancestor account
-- -------------------------------------------------------
CREATE OR REPLACE FUNCTION public.has_role_on_account_or_ancestor(
  target_account_id uuid,
  account_role varchar(50) DEFAULT NULL
)
RETURNS boolean
LANGUAGE sql
SECURITY DEFINER
SET search_path = ''
AS $$
  SELECT EXISTS (
    SELECT 1
    FROM public.accounts_memberships membership
    WHERE membership.user_id = (SELECT auth.uid())
      AND membership.account_id IN (
        SELECT id FROM public.get_account_ancestors(target_account_id)
      )
      AND (
        membership.account_role = has_role_on_account_or_ancestor.account_role
        OR has_role_on_account_or_ancestor.account_role IS NULL
      )
  );
$$;

GRANT EXECUTE ON FUNCTION public.has_role_on_account_or_ancestor(uuid, varchar)
  TO authenticated, service_role;

-- -------------------------------------------------------
-- Core: check permission on account OR any ancestor
-- -------------------------------------------------------
CREATE OR REPLACE FUNCTION public.has_permission_or_ancestor(
  user_id uuid,
  target_account_id uuid,
  permission_name public.app_permissions
)
RETURNS boolean
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = ''
AS $$
BEGIN
  RETURN EXISTS (
    SELECT 1
    FROM public.accounts_memberships am
    JOIN public.role_permissions rp ON am.account_role = rp.role
    WHERE am.user_id = has_permission_or_ancestor.user_id
      AND am.account_id IN (
        SELECT id FROM public.get_account_ancestors(target_account_id)
      )
      AND rp.permission = has_permission_or_ancestor.permission_name
  );
END;
$$;

GRANT EXECUTE ON FUNCTION public.has_permission_or_ancestor(uuid, uuid, public.app_permissions)
  TO authenticated, service_role;

-- -------------------------------------------------------
-- Utility: get all accounts visible to the current user
-- through hierarchy (accounts they belong to + descendants)
-- -------------------------------------------------------
CREATE OR REPLACE FUNCTION public.get_user_visible_accounts()
RETURNS SETOF uuid
LANGUAGE sql
STABLE
SECURITY DEFINER
SET search_path = ''
AS $$
  SELECT DISTINCT d.id
  FROM public.accounts_memberships am
  CROSS JOIN LATERAL public.get_account_descendants(am.account_id) d(id)
  WHERE am.user_id = (SELECT auth.uid());
$$;

GRANT EXECUTE ON FUNCTION public.get_user_visible_accounts()
  TO authenticated, service_role;

-- -------------------------------------------------------
-- Utility: list child accounts of a given account
-- -------------------------------------------------------
CREATE OR REPLACE FUNCTION public.get_child_accounts(parent_id uuid)
RETURNS TABLE (
  id uuid,
  name varchar,
  slug text,
  parent_account_id uuid,
  created_at timestamptz
)
LANGUAGE plpgsql
STABLE
SECURITY DEFINER
SET search_path = ''
AS $$
BEGIN
  -- Only return children if caller has a role on the parent account
  IF NOT public.has_role_on_account(get_child_accounts.parent_id) THEN
    RETURN;
  END IF;

  RETURN QUERY
  SELECT a.id, a.name, a.slug, a.parent_account_id, a.created_at
  FROM public.accounts a
  WHERE a.parent_account_id = get_child_accounts.parent_id
    AND a.is_personal_account = false;
END;
$$;

GRANT EXECUTE ON FUNCTION public.get_child_accounts(uuid)
  TO authenticated, service_role;

-- -------------------------------------------------------
-- RLS: Allow parent accounts to read child account rows
--
-- We add PERMISSIVE policies alongside existing ones.
-- Existing: has_role_on_account(account_id) — direct membership
-- New: has_role_on_account_or_ancestor(account_id) — hierarchy
--
-- Only applied to SELECT (reads). Writes stay per-account.
-- -------------------------------------------------------

-- Members table: parent can see child members
DO $$
BEGIN
  IF NOT EXISTS (
    SELECT 1 FROM pg_policies
    WHERE schemaname = 'public' AND tablename = 'members'
      AND policyname = 'members_hierarchy_read'
  ) THEN
    EXECUTE 'CREATE POLICY members_hierarchy_read ON public.members
      FOR SELECT TO authenticated
      USING (public.has_role_on_account_or_ancestor(account_id))';
  END IF;
END $$;

-- Events table: parent can see child events
DO $$
BEGIN
  IF NOT EXISTS (
    SELECT 1 FROM pg_policies
    WHERE schemaname = 'public' AND tablename = 'events'
      AND policyname = 'events_hierarchy_read'
  ) THEN
    EXECUTE 'CREATE POLICY events_hierarchy_read ON public.events
      FOR SELECT TO authenticated
      USING (public.has_role_on_account_or_ancestor(account_id))';
  END IF;
END $$;

-- Courses table: parent can see child courses
DO $$
BEGIN
  IF NOT EXISTS (
    SELECT 1 FROM pg_policies
    WHERE schemaname = 'public' AND tablename = 'courses'
      AND policyname = 'courses_hierarchy_read'
  ) THEN
    EXECUTE 'CREATE POLICY courses_hierarchy_read ON public.courses
      FOR SELECT TO authenticated
      USING (public.has_role_on_account_or_ancestor(account_id))';
  END IF;
END $$;

-- Member clubs (Verbandsverwaltung): parent can see child clubs
DO $$
BEGIN
  IF NOT EXISTS (
    SELECT 1 FROM pg_policies
    WHERE schemaname = 'public' AND tablename = 'member_clubs'
      AND policyname = 'member_clubs_hierarchy_read'
  ) THEN
    EXECUTE 'CREATE POLICY member_clubs_hierarchy_read ON public.member_clubs
      FOR SELECT TO authenticated
      USING (public.has_role_on_account_or_ancestor(account_id))';
  END IF;
END $$;

-- Accounts table: allow reading child accounts in hierarchy
DO $$
BEGIN
  IF NOT EXISTS (
    SELECT 1 FROM pg_policies
    WHERE schemaname = 'public' AND tablename = 'accounts'
      AND policyname = 'accounts_hierarchy_read'
  ) THEN
    EXECUTE 'CREATE POLICY accounts_hierarchy_read ON public.accounts
      FOR SELECT TO authenticated
      USING (
        id IN (SELECT public.get_user_visible_accounts())
      )';
  END IF;
END $$;
