begin;

create extension "basejump-supabase_test_helpers" version '0.0.6';

select no_plan();

-- =====================================================
-- Member Management Function Tests
-- Tests PG functions for correctness, auth, atomicity
-- =====================================================

-- Setup: create test users and account
select tests.create_supabase_user('owner', 'owner@test.com');
select tests.create_supabase_user('member_user', 'member@test.com');
select tests.create_supabase_user('outsider', 'outsider@test.com');

select makerkit.set_identifier('owner', 'owner@test.com');
select makerkit.set_identifier('member_user', 'member@test.com');
select makerkit.set_identifier('outsider', 'outsider@test.com');

-- Create a team account owned by 'owner'
set local role service_role;
select public.create_team_account('Test Verein', tests.get_supabase_uid('owner'));

-- Get account ID
select makerkit.authenticate_as('owner');
\set test_account_id '(select id from public.accounts where slug = ''test-verein'' limit 1)'

-- Grant members.write permission to owner
set local role postgres;
insert into public.role_permissions (role, permission)
values ('owner', 'members.write')
on conflict do nothing;

-- -------------------------------------------------------
-- Test: get_next_member_number
-- -------------------------------------------------------
select makerkit.authenticate_as('owner');

select is(
  public.get_next_member_number(:test_account_id),
  '0001',
  'First member number should be 0001'
);

-- Insert a member to test incrementing
set local role service_role;
insert into public.members (account_id, first_name, last_name, member_number, status, entry_date, created_by, updated_by)
values (:test_account_id, 'Max', 'Mustermann', '0001', 'active', current_date,
        tests.get_supabase_uid('owner'), tests.get_supabase_uid('owner'));

select makerkit.authenticate_as('owner');

select is(
  public.get_next_member_number(:test_account_id),
  '0002',
  'Second member number should be 0002'
);

-- -------------------------------------------------------
-- Test: get_member_quick_stats
-- -------------------------------------------------------
select isnt_empty(
  $$ select * from public.get_member_quick_stats((select id from public.accounts where slug = 'test-verein' limit 1)) $$,
  'Quick stats returns data for account with members'
);

-- -------------------------------------------------------
-- Test: check_duplicate_member
-- -------------------------------------------------------
select isnt_empty(
  $$ select * from public.check_duplicate_member(
    (select id from public.accounts where slug = 'test-verein' limit 1),
    'Max', 'Mustermann', null
  ) $$,
  'Duplicate check finds existing member by name'
);

select is_empty(
  $$ select * from public.check_duplicate_member(
    (select id from public.accounts where slug = 'test-verein' limit 1),
    'Nonexistent', 'Person', null
  ) $$,
  'Duplicate check returns empty for non-matching name'
);

-- -------------------------------------------------------
-- Test: approve_application
-- -------------------------------------------------------

-- Create a test application
set local role service_role;
insert into public.membership_applications (
  account_id, first_name, last_name, email, status
) values (
  :test_account_id, 'Anna', 'Bewerberin', 'anna@test.com', 'submitted'
);

select makerkit.authenticate_as('owner');

-- Approve it
select lives_ok(
  $$ select public.approve_application(
    (select id from public.membership_applications where email = 'anna@test.com'),
    tests.get_supabase_uid('owner')
  ) $$,
  'Owner can approve application'
);

-- Verify member was created
select isnt_empty(
  $$ select * from public.members where first_name = 'Anna' and last_name = 'Bewerberin' $$,
  'Approved application creates a member'
);

-- Verify application status changed
select is(
  (select status from public.membership_applications where email = 'anna@test.com'),
  'approved'::public.application_status,
  'Application status is approved'
);

-- -------------------------------------------------------
-- Test: reject_application
-- -------------------------------------------------------
set local role service_role;
insert into public.membership_applications (
  account_id, first_name, last_name, email, status
) values (
  :test_account_id, 'Bob', 'Abgelehnt', 'bob@test.com', 'submitted'
);

select makerkit.authenticate_as('owner');

select lives_ok(
  $$ select public.reject_application(
    (select id from public.membership_applications where email = 'bob@test.com'),
    tests.get_supabase_uid('owner'),
    'Nicht qualifiziert'
  ) $$,
  'Owner can reject application'
);

select is(
  (select status from public.membership_applications where email = 'bob@test.com'),
  'rejected'::public.application_status,
  'Application status is rejected'
);

-- -------------------------------------------------------
-- Test: approve_application — already approved should fail
-- -------------------------------------------------------
-- Verify the re-approval throws with status message
prepare approve_again as select public.approve_application(
  (select id from public.membership_applications where email = 'anna@test.com'),
  tests.get_supabase_uid('owner')
);
select throws_ok(
  'approve_again',
  'P0001',
  'Application is not in a reviewable state (current: approved)',
  'Cannot approve already-approved application'
);

-- -------------------------------------------------------
-- Test: get_member_timeline
-- -------------------------------------------------------
-- The member creation via approve_application should have generated an audit entry
select isnt_empty(
  $$ select * from public.get_member_timeline(
    (select id from public.members where first_name = 'Anna' limit 1),
    1, 50, null
  ) $$,
  'Member timeline has entries after creation'
);

-- -------------------------------------------------------
-- Test: log_member_audit_event
-- -------------------------------------------------------
select makerkit.authenticate_as('owner');

select lives_ok(
  $$ select public.log_member_audit_event(
    (select id from public.members where first_name = 'Max' limit 1),
    (select id from public.accounts where slug = 'test-verein' limit 1),
    'note_added',
    '{"note": "Test note"}'::jsonb,
    '{}'::jsonb
  ) $$,
  'Owner can log audit event for member'
);

-- -------------------------------------------------------
-- Test: outsider cannot access functions
-- -------------------------------------------------------
select makerkit.authenticate_as('outsider');

-- Outsider should get an error when calling get_next_member_number
prepare outsider_member_number as select public.get_next_member_number(
  (select id from public.accounts where slug = 'test-verein' limit 1)
);
select throws_ok(
  'outsider_member_number',
  'P0001',
  null,
  'Outsider cannot call get_next_member_number'
);

select * from finish();

rollback;
