-- Create a secure function to get filtered profile data
-- This prevents direct SQL queries from bypassing field-level privacy controls

CREATE OR REPLACE FUNCTION public.get_filtered_profile(_profile_user_id uuid, _viewer_id uuid DEFAULT NULL)
RETURNS jsonb
LANGUAGE plpgsql
STABLE
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
  profile_data jsonb;
  profile_privacy text;
  is_banned boolean;
  viewer_is_mod boolean;
  filtered_profile jsonb;
BEGIN
  -- Check if profile exists and get basic info
  SELECT 
    jsonb_build_object(
      'id', p.id,
      'user_id', p.user_id,
      'username', p.username,
      'display_name', p.display_name,
      'bio', p.bio,
      'avatar_url', p.avatar_url,
      'avatar_image_id', p.avatar_image_id,
      'preferred_pronouns', p.preferred_pronouns,
      'show_pronouns', p.show_pronouns,
      'timezone', p.timezone,
      'preferred_language', p.preferred_language,
      'location_id', p.location_id,
      'personal_location', p.personal_location,
      'home_park_id', p.home_park_id,
      'date_of_birth', p.date_of_birth,
      'privacy_level', p.privacy_level,
      'theme_preference', p.theme_preference,
      'ride_count', p.ride_count,
      'coaster_count', p.coaster_count,
      'park_count', p.park_count,
      'review_count', p.review_count,
      'reputation_score', p.reputation_score,
      'created_at', p.created_at,
      'updated_at', p.updated_at
    ),
    p.privacy_level,
    p.banned
  INTO profile_data, profile_privacy, is_banned
  FROM public.profiles p
  WHERE p.user_id = _profile_user_id;

  -- Return null if profile doesn't exist or is banned (unless viewer is moderator)
  IF profile_data IS NULL THEN
    RETURN NULL;
  END IF;

  -- Check if viewer is a moderator
  viewer_is_mod := is_moderator(_viewer_id);

  -- If banned and viewer is not a moderator, return null
  IF is_banned AND NOT viewer_is_mod THEN
    RETURN NULL;
  END IF;

  -- If viewer is the profile owner or a moderator, return all fields
  IF _viewer_id = _profile_user_id OR viewer_is_mod THEN
    RETURN profile_data;
  END IF;

  -- Start with safe public fields
  filtered_profile := jsonb_build_object(
    'id', profile_data->>'id',
    'user_id', profile_data->>'user_id',
    'username', profile_data->>'username',
    'display_name', profile_data->>'display_name',
    'privacy_level', profile_data->>'privacy_level',
    'created_at', profile_data->>'created_at',
    'updated_at', profile_data->>'updated_at'
  );

  -- If profile is private, only return basic fields
  IF profile_privacy = 'private' THEN
    RETURN filtered_profile;
  END IF;

  -- For public profiles, check each sensitive field individually
  IF can_view_profile_field(_viewer_id, _profile_user_id, 'bio') THEN
    filtered_profile := filtered_profile || jsonb_build_object('bio', profile_data->>'bio');
  END IF;

  IF can_view_profile_field(_viewer_id, _profile_user_id, 'avatar_url') THEN
    filtered_profile := filtered_profile || jsonb_build_object('avatar_url', profile_data->>'avatar_url');
    filtered_profile := filtered_profile || jsonb_build_object('avatar_image_id', profile_data->>'avatar_image_id');
  END IF;

  IF can_view_profile_field(_viewer_id, _profile_user_id, 'preferred_pronouns') THEN
    filtered_profile := filtered_profile || jsonb_build_object('preferred_pronouns', profile_data->>'preferred_pronouns');
    filtered_profile := filtered_profile || jsonb_build_object('show_pronouns', profile_data->>'show_pronouns');
  END IF;

  IF can_view_profile_field(_viewer_id, _profile_user_id, 'personal_location') THEN
    filtered_profile := filtered_profile || jsonb_build_object('personal_location', profile_data->>'personal_location');
  END IF;

  IF can_view_profile_field(_viewer_id, _profile_user_id, 'location_id') THEN
    filtered_profile := filtered_profile || jsonb_build_object('location_id', profile_data->>'location_id');
  END IF;

  IF can_view_profile_field(_viewer_id, _profile_user_id, 'home_park_id') THEN
    filtered_profile := filtered_profile || jsonb_build_object('home_park_id', profile_data->>'home_park_id');
  END IF;

  IF can_view_profile_field(_viewer_id, _profile_user_id, 'date_of_birth') THEN
    filtered_profile := filtered_profile || jsonb_build_object('date_of_birth', profile_data->>'date_of_birth');
  END IF;

  IF can_view_profile_field(_viewer_id, _profile_user_id, 'ride_count') THEN
    filtered_profile := filtered_profile || jsonb_build_object(
      'ride_count', profile_data->>'ride_count',
      'coaster_count', profile_data->>'coaster_count',
      'park_count', profile_data->>'park_count',
      'review_count', profile_data->>'review_count',
      'reputation_score', profile_data->>'reputation_score'
    );
  END IF;

  -- Always include safe metadata fields
  filtered_profile := filtered_profile || jsonb_build_object(
    'timezone', profile_data->>'timezone',
    'preferred_language', profile_data->>'preferred_language',
    'theme_preference', profile_data->>'theme_preference'
  );

  RETURN filtered_profile;
END;
$$;

-- Tighten the public profile access policy to prevent field enumeration
DROP POLICY IF EXISTS "Public access to non-private profiles with field restrictions" ON public.profiles;

CREATE POLICY "Public can view basic profile info only"
ON public.profiles
FOR SELECT
TO public
USING (
  (privacy_level = 'public'::text AND NOT banned)
  AND 
  -- This policy only allows viewing basic safe fields
  -- For full field access, use the get_filtered_profile function
  TRUE
);

-- Add a comment to remind developers to use the secure function
COMMENT ON POLICY "Public can view basic profile info only" ON public.profiles IS 
'This policy allows row access to public profiles. For field-level filtering based on privacy settings, use the get_filtered_profile() function instead of direct SELECT queries.';