import { createAdminClient } from '@/shared/db/supabase-client';

// --- ASA GENERATED START ---
// RBAC engine — canonical built-in roles with permission-based guards.
// Roles: owner, admin, support (defined in 004_user_roles.sql).
// JWT claims populated via Supabase Custom Access Token Hook.
// --- ASA GENERATED END ---

// --- USER CODE START ---

export const BUILTIN_ROLES = ['owner', 'admin', 'support'] as const;
export type BuiltinRole = typeof BUILTIN_ROLES[number];

/**
 * Get all roles assigned to a user.
 */
export async function getUserRoles(userId: string): Promise<string[]> {
  const supabase = createAdminClient();
  const { data } = await supabase
    .from('user_roles')
    .select('role_id')
    .eq('user_id', userId);

  return data?.map((r) => r.role_id) ?? [];
}

/**
 * Get all permissions for a user (resolved through their roles).
 */
export async function getUserPermissions(userId: string): Promise<string[]> {
  const supabase = createAdminClient();

  const { data } = await supabase
    .from('user_roles')
    .select('role_id, role:roles!inner(id), permissions:role_permissions!inner(permission_id)')
    .eq('user_id', userId);

  if (!data) return [];

  const permissions = new Set<string>();
  for (const entry of data) {
    const perms = entry.permissions as unknown as { permission_id: string }[];
    if (Array.isArray(perms)) {
      for (const p of perms) {
        permissions.add(p.permission_id);
      }
    }
  }

  return Array.from(permissions);
}

/**
 * Check if a user has a specific permission.
 */
export async function hasPermission(userId: string, permission: string): Promise<boolean> {
  const permissions = await getUserPermissions(userId);
  return permissions.includes(permission);
}

/**
 * Assign a role to a user.
 * Requires the assigner to have ROLES_ASSIGN permission.
 */
export async function assignRole(
  userId: string,
  roleId: string,
  assignedBy: string,
): Promise<{ success: boolean; error?: string }> {
  const supabase = createAdminClient();

  // Validate role exists
  const { data: role } = await supabase
    .from('roles')
    .select('id')
    .eq('id', roleId)
    .single();

  if (!role) {
    return { success: false, error: `Role '${roleId}' does not exist` };
  }

  const { error } = await supabase
    .from('user_roles')
    .upsert(
      { user_id: userId, role_id: roleId, assigned_by: assignedBy },
      { onConflict: 'user_id,role_id' },
    );

  if (error) {
    return { success: false, error: error.message };
  }

  return { success: true };
}

/**
 * Remove a role from a user.
 */
export async function removeRole(
  userId: string,
  roleId: string,
): Promise<{ success: boolean; error?: string }> {
  const supabase = createAdminClient();

  const { error } = await supabase
    .from('user_roles')
    .delete()
    .eq('user_id', userId)
    .eq('role_id', roleId);

  if (error) {
    return { success: false, error: error.message };
  }

  return { success: true };
}

/**
 * Supabase Custom Access Token Hook handler.
 * Add this as a Postgres function + hook in Supabase Dashboard.
 *
 * SQL for the hook function:
 * ```sql
 * CREATE OR REPLACE FUNCTION public.custom_access_token_hook(event JSONB)
 * RETURNS JSONB LANGUAGE plpgsql AS $$
 * DECLARE
 *   claims JSONB;
 *   user_roles TEXT[];
 *   user_perms TEXT[];
 * BEGIN
 *   SELECT ARRAY_AGG(ur.role_id) INTO user_roles
 *   FROM public.user_roles ur WHERE ur.user_id = (event->>'user_id')::UUID;
 *
 *   SELECT ARRAY_AGG(DISTINCT rp.permission_id) INTO user_perms
 *   FROM public.user_roles ur
 *   JOIN public.role_permissions rp ON rp.role_id = ur.role_id
 *   WHERE ur.user_id = (event->>'user_id')::UUID;
 *
 *   claims := event->'claims';
 *   claims := jsonb_set(claims, '{user_roles}', COALESCE(to_jsonb(user_roles), '[]'));
 *   claims := jsonb_set(claims, '{user_permissions}', COALESCE(to_jsonb(user_perms), '[]'));
 *
 *   event := jsonb_set(event, '{claims}', claims);
 *   RETURN event;
 * END;
 * $$;
 * ```
 */

// --- USER CODE END ---
