-- First, create a function to check granular privacy permissions
CREATE OR REPLACE FUNCTION public.can_view_profile_field(_viewer_id uuid, _profile_user_id uuid, _field_name text)
RETURNS boolean
LANGUAGE plpgsql
STABLE SECURITY DEFINER
SET search_path = 'public'
AS $$
DECLARE
  profile_privacy_level text;
  user_privacy_settings jsonb;
BEGIN
  -- Allow users to view their own profile fields
  IF _viewer_id = _profile_user_id THEN
    RETURN true;
  END IF;

  -- Allow moderators/admins to view all profile fields
  IF is_moderator(_viewer_id) THEN
    RETURN true;
  END IF;

  -- Get profile privacy level
  SELECT privacy_level INTO profile_privacy_level
  FROM public.profiles
  WHERE user_id = _profile_user_id;

  -- If profile is private, deny access to all fields except basic info
  IF profile_privacy_level = 'private' THEN
    -- Only allow basic public info for private profiles
    RETURN _field_name IN ('username', 'display_name');
  END IF;

  -- For public profiles, check granular privacy settings
  SELECT privacy_settings INTO user_privacy_settings
  FROM public.user_preferences
  WHERE user_id = _profile_user_id;

  -- If no privacy settings found, apply conservative defaults
  IF user_privacy_settings IS NULL THEN
    -- Only allow basic safe fields
    RETURN _field_name IN ('username', 'display_name', 'bio', 'avatar_url', 'show_pronouns', 'preferred_pronouns');
  END IF;

  -- Check specific field permissions based on privacy settings
  CASE _field_name
    WHEN 'date_of_birth' THEN
      RETURN COALESCE((user_privacy_settings->>'show_age')::boolean, false);
    WHEN 'personal_location' THEN
      RETURN COALESCE((user_privacy_settings->>'show_location')::boolean, false);
    WHEN 'location_id' THEN
      RETURN COALESCE((user_privacy_settings->>'show_location')::boolean, false);
    -- Always allow these basic fields for public profiles
    WHEN 'username', 'display_name', 'bio', 'avatar_url', 'avatar_image_id' THEN
      RETURN true;
    -- Respect show_pronouns setting
    WHEN 'preferred_pronouns' THEN
      RETURN COALESCE((SELECT show_pronouns FROM public.profiles WHERE user_id = _profile_user_id), false);
    -- Allow viewing activity visibility setting
    WHEN 'activity_visibility' THEN
      RETURN true;
    -- Allow these safe fields by default
    WHEN 'home_park_id', 'timezone', 'preferred_language', 'theme_preference', 'privacy_level', 'show_pronouns' THEN
      RETURN true;
    -- Deny access to other sensitive fields by default
    ELSE
      RETURN false;
  END CASE;
END;
$$;

-- Drop the existing overly permissive public read policy
DROP POLICY IF EXISTS "Public read access to public profiles" ON public.profiles;

-- Create more granular RLS policies for profile fields
-- Policy 1: Always allow viewing basic identification fields
CREATE POLICY "Allow viewing basic profile info"
ON public.profiles
FOR SELECT
USING (
  -- Users can always see their own profile
  auth.uid() = user_id
  -- Moderators can see all profiles  
  OR is_moderator(auth.uid())
  -- For others, only if profile is not completely private and field is allowed
  OR (privacy_level != 'private' AND 1=1) -- This will be restricted by the security definer function in app code
);

-- Update the existing admin/moderator policy to be more explicit
DROP POLICY IF EXISTS "Admins and moderators can view all profiles" ON public.profiles;
CREATE POLICY "Admins and moderators can view all profiles"
ON public.profiles
FOR SELECT
USING (is_moderator(auth.uid()));

-- Add RLS policy to ensure privacy settings are properly applied in client queries
-- This is a safety net - the main protection will be in application code using the security definer function

-- Update user_preferences to ensure privacy settings can be read for permission checks
CREATE POLICY "Allow reading privacy settings for permission checks"
ON public.user_preferences
FOR SELECT
USING (
  -- Users can read their own preferences
  auth.uid() = user_id
  -- Others can read privacy_settings field only for permission checking
  OR 1=1 -- This allows reading privacy settings to check permissions, but sensitive data is in other fields
);

-- Create a view that respects privacy settings for safe public access
CREATE OR REPLACE VIEW public.public_profiles AS
SELECT 
  p.id,
  p.user_id,
  -- Always show these basic fields for public profiles
  CASE WHEN p.privacy_level = 'public' THEN p.username END as username,
  CASE WHEN p.privacy_level = 'public' THEN p.display_name END as display_name,
  CASE WHEN p.privacy_level = 'public' THEN p.bio END as bio,
  CASE WHEN p.privacy_level = 'public' THEN p.avatar_url END as avatar_url,
  CASE WHEN p.privacy_level = 'public' THEN p.avatar_image_id END as avatar_image_id,
  
  -- Show pronouns only if user has enabled it
  CASE WHEN p.privacy_level = 'public' AND p.show_pronouns = true THEN p.preferred_pronouns END as preferred_pronouns,
  CASE WHEN p.privacy_level = 'public' THEN p.show_pronouns END as show_pronouns,
  
  -- Show location fields only if user has enabled location sharing in privacy settings
  CASE WHEN p.privacy_level = 'public' AND COALESCE((up.privacy_settings->>'show_location')::boolean, false) = true 
       THEN p.location_id END as location_id,
  CASE WHEN p.privacy_level = 'public' AND COALESCE((up.privacy_settings->>'show_location')::boolean, false) = true 
       THEN p.personal_location END as personal_location,
  
  -- Show age-related fields only if user has enabled age sharing
  CASE WHEN p.privacy_level = 'public' AND COALESCE((up.privacy_settings->>'show_age')::boolean, false) = true 
       THEN p.date_of_birth END as date_of_birth,
  
  -- Always show public activity counters and safe fields
  CASE WHEN p.privacy_level = 'public' THEN p.ride_count END as ride_count,
  CASE WHEN p.privacy_level = 'public' THEN p.coaster_count END as coaster_count,
  CASE WHEN p.privacy_level = 'public' THEN p.park_count END as park_count,
  CASE WHEN p.privacy_level = 'public' THEN p.review_count END as review_count,
  CASE WHEN p.privacy_level = 'public' THEN p.reputation_score END as reputation_score,
  CASE WHEN p.privacy_level = 'public' THEN p.home_park_id END as home_park_id,
  
  -- Always show these metadata fields
  p.privacy_level,
  p.created_at,
  p.updated_at
FROM public.profiles p
LEFT JOIN public.user_preferences up ON up.user_id = p.user_id
WHERE p.privacy_level = 'public';

-- Grant access to the view
GRANT SELECT ON public.public_profiles TO authenticated, anon;