/**
 * B-series: Collective-level RLS — roles, invitations, member management.
 */
import { describe, it, expect, afterAll } from 'vitest';
import { createClientAs, createAdminClient } from '../src/supabase-clients.js';
import {
	ANA_ID,
	BORJA_ID,
	DAVID_ID,
	EVA_ID,
	COLLECTIVE_ID
} from '../src/seed-constants.js';

const admin = createAdminClient();

// Invitations created during tests — cleaned up in afterAll
const createdInvitationIds: string[] = [];

afterAll(async () => {
	if (createdInvitationIds.length > 0) {
		await admin
			.from('collective_invitations')
			.delete()
			.in('id', createdInvitationIds);
	}
});

describe('Collective read access', () => {
	it('B-02: member (Borja) can read the collective', async () => {
		const borja = await createClientAs(BORJA_ID);
		const { data, error } = await borja
			.from('collectives')
			.select('id, name')
			.eq('id', COLLECTIVE_ID)
			.single();
		expect(error).toBeNull();
		expect(data?.id).toBe(COLLECTIVE_ID);
	});

	it('B-03: guest (David) can read the collective', async () => {
		const david = await createClientAs(DAVID_ID);
		const { data, error } = await david
			.from('collectives')
			.select('id')
			.eq('id', COLLECTIVE_ID)
			.single();
		expect(error).toBeNull();
		expect(data?.id).toBe(COLLECTIVE_ID);
	});

	it('B-04: member can read the member list', async () => {
		const borja = await createClientAs(BORJA_ID);
		const { data, error } = await borja
			.from('collective_members')
			.select('user_id')
			.eq('collective_id', COLLECTIVE_ID);
		expect(error).toBeNull();
		expect(data!.length).toBeGreaterThanOrEqual(4);
	});
});

describe('Collective update — admin only', () => {
	it('B-05: admin (Ana) can rename the collective', async () => {
		const ana = await createClientAs(ANA_ID);
		const { error } = await ana
			.from('collectives')
			.update({ name: 'Casa García-López' })
			.eq('id', COLLECTIVE_ID);
		expect(error).toBeNull();
	});

	it('B-06: member (Borja) cannot rename the collective', async () => {
		const borja = await createClientAs(BORJA_ID);
		const { error, count } = await borja
			.from('collectives')
			.update({ name: 'Borja takeover' })
			.eq('id', COLLECTIVE_ID);
		// PostgREST returns 200 with 0 rows updated when blocked by RLS
		expect(error).toBeNull();
		// Verify the name didn't change
		const { data } = await admin.from('collectives').select('name').eq('id', COLLECTIVE_ID).single();
		expect(data?.name).toBe('Casa García-López');
	});

	it('B-07: guest (David) cannot rename the collective', async () => {
		const david = await createClientAs(DAVID_ID);
		await david
			.from('collectives')
			.update({ name: 'David takeover' })
			.eq('id', COLLECTIVE_ID);
		const { data } = await admin.from('collectives').select('name').eq('id', COLLECTIVE_ID).single();
		expect(data?.name).toBe('Casa García-López');
	});
});

describe('Invitations — admin only', () => {
	it('B-08: admin (Ana) can create an invitation', async () => {
		const ana = await createClientAs(ANA_ID);
		const { data, error } = await ana
			.from('collective_invitations')
			.insert({
				collective_id: COLLECTIVE_ID,
				created_by: ANA_ID,
				role: 'member'
			})
			.select('id')
			.single();
		expect(error).toBeNull();
		expect(data?.id).toBeTruthy();
		if (data?.id) createdInvitationIds.push(data.id);
	});

	it('B-09: member (Borja) cannot create an invitation', async () => {
		const borja = await createClientAs(BORJA_ID);
		const { data, error } = await borja
			.from('collective_invitations')
			.insert({
				collective_id: COLLECTIVE_ID,
				created_by: BORJA_ID,
				role: 'member'
			})
			.select('id')
			.single();
		expect(data).toBeNull();
		expect(error).not.toBeNull();
	});

	it('B-10: guest (David) cannot create an invitation', async () => {
		const david = await createClientAs(DAVID_ID);
		const { data, error } = await david
			.from('collective_invitations')
			.insert({
				collective_id: COLLECTIVE_ID,
				created_by: DAVID_ID,
				role: 'guest'
			})
			.select('id')
			.single();
		expect(data).toBeNull();
		expect(error).not.toBeNull();
	});

	it('B-11: admin can read the invitations they created', async () => {
		const ana = await createClientAs(ANA_ID);
		const { data, error } = await ana
			.from('collective_invitations')
			.select('id')
			.eq('collective_id', COLLECTIVE_ID);
		expect(error).toBeNull();
		expect(data!.length).toBeGreaterThanOrEqual(1);
	});

	it('B-12: member (Borja) cannot update an invitation directly', async () => {
		// Accepting invitations must go through the accept_invitation() RPC —
		// direct UPDATE is denied by the update_deny policy.
		const borja = await createClientAs(BORJA_ID);
		const { data: inv } = await admin
			.from('collective_invitations')
			.select('id')
			.eq('collective_id', COLLECTIVE_ID)
			.limit(1)
			.single();

		if (!inv?.id) return; // skip if no invitations exist

		const { error } = await borja
			.from('collective_invitations')
			.update({ accepted_at: new Date().toISOString() })
			.eq('id', inv.id);
		// RLS denies all direct UPDATEs — PostgREST may return error or 0 rows
		const { data: check } = await admin
			.from('collective_invitations')
			.select('accepted_at')
			.eq('id', inv.id)
			.single();
		expect(check?.accepted_at).toBeNull();
	});

	it('B-13: Eva (non-member) cannot create an invitation', async () => {
		const eva = await createClientAs(EVA_ID);
		const { data, error } = await eva
			.from('collective_invitations')
			.insert({
				collective_id: COLLECTIVE_ID,
				created_by: EVA_ID,
				role: 'member'
			})
			.select('id')
			.single();
		expect(data).toBeNull();
		expect(error).not.toBeNull();
	});
});
