begin;
select plan(19); -- Total number of tests

-- ============================================================================
-- RLS Enabled Test
-- ============================================================================

SELECT is(
    (SELECT relrowsecurity FROM pg_class WHERE relname = 'notifications' AND relnamespace = 'public'::regnamespace),
    true,
    'RLS should be enabled on notifications table'
);

-- ============================================================================
-- Notifications Table RLS Policies
-- ============================================================================

SELECT ok(
    (SELECT COUNT(*) FROM pg_policies WHERE tablename = 'notifications' AND policyname = 'Users can view their own notifications') > 0,
    'Policy for viewing own notifications should exist'
);

SELECT ok(
    (SELECT COUNT(*) FROM pg_policies WHERE tablename = 'notifications' AND policyname = 'Users can mark their own notifications as read') > 0,
    'Policy for marking notifications as read should exist'
);

-- Test policy commands
SELECT is(
    (SELECT cmd FROM pg_policies WHERE tablename = 'notifications' AND policyname = 'Users can view their own notifications' LIMIT 1),
    'SELECT',
    'View notifications policy should be for SELECT'
);

SELECT is(
    (SELECT cmd FROM pg_policies WHERE tablename = 'notifications' AND policyname = 'Users can mark their own notifications as read' LIMIT 1),
    'UPDATE',
    'Mark as read policy should be for UPDATE'
);

-- Test policy uses auth.uid() for isolation
SELECT ok(
    (SELECT qual::text FROM pg_policies 
     WHERE tablename = 'notifications' 
     AND policyname = 'Users can view their own notifications' 
     LIMIT 1) LIKE '%auth.uid()%',
    'SELECT policy should use auth.uid() for user isolation'
);

-- Test UPDATE policy allows updating read_at
SELECT ok(
    (SELECT with_check::text FROM pg_policies 
     WHERE tablename = 'notifications' 
     AND policyname = 'Users can mark their own notifications as read' 
     LIMIT 1) LIKE '%read_at%',
    'UPDATE policy should check read_at field'
);

-- ============================================================================
-- Notifications Behavior Tests with Mock Data
-- ============================================================================

-- Create test users and generate some notifications
DO $$
DECLARE
    user1_id uuid := gen_random_uuid();
    user2_id uuid := gen_random_uuid();
    test_tablo_id text;
BEGIN
    -- Insert test users
    INSERT INTO auth.users (id, instance_id, aud, role, email, encrypted_password, email_confirmed_at, created_at, updated_at)
    VALUES 
        (user1_id, '00000000-0000-0000-0000-000000000000', 'authenticated', 'authenticated', 'notifrlsuser1_' || user1_id::text || '@test.com', 'encrypted', now(), now(), now()),
        (user2_id, '00000000-0000-0000-0000-000000000000', 'authenticated', 'authenticated', 'notifrlsuser2_' || user2_id::text || '@test.com', 'encrypted', now(), now(), now())
    ON CONFLICT DO NOTHING;
    
    -- Insert test profiles
    INSERT INTO public.profiles (id, email, first_name, last_name, short_user_id)
    VALUES 
        (user1_id, 'notifrlsuser1_' || user1_id::text || '@test.com', 'NotifRLS', 'User1', substring(user1_id::text from 1 for 8)),
        (user2_id, 'notifrlsuser2_' || user2_id::text || '@test.com', 'NotifRLS', 'User2', substring(user2_id::text from 1 for 8))
    ON CONFLICT DO NOTHING;
    
    -- Set auth context to user1 for creating test data
    PERFORM set_config('request.jwt.claims', json_build_object('sub', user1_id::text)::text, true);
    
    -- Create a tablo as user1
    INSERT INTO public.tablos (owner_id, name, status, position)
    VALUES (user1_id, 'RLS Test Tablo', 'todo', 0)
    RETURNING id INTO test_tablo_id;
    
    -- Grant access to user2
    INSERT INTO public.tablo_access (tablo_id, user_id, granted_by, is_active, is_admin)
    VALUES (test_tablo_id, user2_id, user1_id, true, false);
    
    -- Update tablo to trigger notification for user2
    UPDATE public.tablos 
    SET name = 'RLS Test Tablo Updated'
    WHERE id = test_tablo_id;
    
    -- Store test IDs
    PERFORM set_config('test.rls_user1_id', user1_id::text, true);
    PERFORM set_config('test.rls_user2_id', user2_id::text, true);
    PERFORM set_config('test.rls_tablo_id', test_tablo_id, true);
END $$;

-- Test: Notifications exist for test users
SELECT ok(
    (SELECT COUNT(*) FROM public.notifications 
     WHERE user_id = current_setting('test.rls_user2_id')::uuid) > 0,
    'Notifications should exist for test user2'
);

-- Test: User2 received notification about tablo update
SELECT ok(
    (SELECT COUNT(*) FROM public.notifications 
     WHERE user_id = current_setting('test.rls_user2_id')::uuid
     AND entity_type = 'tablos'
     AND entity_id = current_setting('test.rls_tablo_id')) > 0,
    'User2 should have notification for tablo update'
);

-- Test: Actor (user1) did not receive notification for their own action
SELECT is(
    (SELECT COUNT(*)::integer FROM public.notifications 
     WHERE user_id = current_setting('test.rls_user1_id')::uuid
     AND actor_id = current_setting('test.rls_user1_id')::uuid
     AND entity_id = current_setting('test.rls_tablo_id')),
    0,
    'User should not receive notifications for their own actions'
);

-- Test: Notifications have proper structure
SELECT ok(
    (SELECT COUNT(*) FROM public.notifications 
     WHERE user_id = current_setting('test.rls_user2_id')::uuid
     AND message IS NOT NULL
     AND length(message->>'en') > 0
     AND length(message->>'fr') > 0) > 0,
    'Notifications should have non-empty messages in both en and fr'
);

SELECT ok(
    (SELECT COUNT(*) FROM public.notifications 
     WHERE user_id = current_setting('test.rls_user2_id')::uuid
     AND metadata IS NOT NULL
     AND jsonb_typeof(metadata) = 'object') > 0,
    'Notifications should have valid JSONB metadata'
);

SELECT ok(
    (SELECT COUNT(*) FROM public.notifications 
     WHERE user_id = current_setting('test.rls_user2_id')::uuid
     AND action_type IN ('created', 'updated')) > 0,
    'Notifications should have valid action_type'
);

-- ============================================================================
-- Test Notification Updates (Mark as Read)
-- ============================================================================

-- Test: Update read_at on a notification
DO $$
DECLARE
    test_notif_id uuid;
BEGIN
    -- Get an unread notification for user2
    SELECT id INTO test_notif_id 
    FROM public.notifications 
    WHERE user_id = current_setting('test.rls_user2_id')::uuid 
    AND read_at IS NULL
    LIMIT 1;
    
    IF test_notif_id IS NOT NULL THEN
        -- Update the notification
        UPDATE public.notifications 
        SET read_at = now() 
        WHERE id = test_notif_id;
        
        PERFORM set_config('test.updated_notif_id', test_notif_id::text, true);
        PERFORM set_config('test.notif_was_updated', 'true', true);
    ELSE
        PERFORM set_config('test.notif_was_updated', 'false', true);
        PERFORM set_config('test.updated_notif_id', '00000000-0000-0000-0000-000000000000', true);
    END IF;
END $$;

-- Verify the update worked
SELECT ok(
    CASE 
        WHEN current_setting('test.notif_was_updated', true) = 'true' THEN
            (SELECT read_at IS NOT NULL 
             FROM public.notifications 
             WHERE id = current_setting('test.updated_notif_id', true)::uuid 
             LIMIT 1)
        ELSE true  -- Skip if no notification was found
    END,
    'Notification should be updatable with read_at timestamp'
);

-- ============================================================================
-- Test Data Isolation
-- ============================================================================

-- Test: Count notifications for user1 vs user2
SELECT ok(
    (SELECT COUNT(*) FROM public.notifications WHERE user_id = current_setting('test.rls_user1_id')::uuid) >= 0,
    'User1 notifications count should be valid'
);

SELECT ok(
    (SELECT COUNT(*) FROM public.notifications WHERE user_id = current_setting('test.rls_user2_id')::uuid) > 0,
    'User2 should have at least one notification'
);

-- ============================================================================
-- Foreign Key Constraints Tests
-- ============================================================================

SELECT has_fk('public', 'notifications', 'notifications should have foreign key constraints');

-- Test that notifications.user_id references auth.users.id
SELECT fk_ok(
    'public', 'notifications', 'user_id',
    'auth', 'users', 'id',
    'notifications.user_id should reference auth.users.id'
);

-- Test that notifications.actor_id references auth.users.id
SELECT fk_ok(
    'public', 'notifications', 'actor_id',
    'auth', 'users', 'id',
    'notifications.actor_id should reference auth.users.id'
);

select * from finish();
rollback;
