/**
 * T-series: trash RPCs (restore_list, hard_delete_list) — Fase 10.4.
 *
 * Verifies that the SECURITY DEFINER functions return what the UI store
 * expects: restore brings the list back to active (visible in loadLists),
 * hard_delete removes it permanently, and both functions guard on caller
 * role (guest rejected, non-member rejected).
 */
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { createClientAs, createAdminClient } from '../src/supabase-clients.js';
import { sql, closePool } from '../src/db-helpers.js';
import {
	BORJA_ID,
	DAVID_ID,
	EVA_ID,
	COLLECTIVE_ID
} from '../src/seed-constants.js';

const admin = createAdminClient();
const trashedIds: string[] = [];

afterAll(async () => {
	if (trashedIds.length) {
		await admin.from('shopping_lists').delete().in('id', trashedIds);
	}
	await closePool();
});

async function makeTrashedList(): Promise<string> {
	const r = await sql(
		`INSERT INTO public.shopping_lists (collective_id, name, status, created_by, deleted_at)
		 VALUES ($1, 'Trash RPC test', 'active', $2, now() - interval '1 hour')
		 RETURNING id`,
		[COLLECTIVE_ID, BORJA_ID]
	);
	const id = r.rows[0].id as string;
	trashedIds.push(id);
	return id;
}

describe('Trash RPCs', () => {
	it('T-10: member restore brings list back to the active listing', async () => {
		const id = await makeTrashedList();
		const borja = await createClientAs(BORJA_ID);

		const { error: rpcErr } = await borja.rpc('restore_list', { p_list_id: id });
		expect(rpcErr).toBeNull();

		const { data } = await admin
			.from('shopping_lists')
			.select('deleted_at')
			.eq('id', id)
			.single();
		expect(data?.deleted_at).toBeNull();

		// Visible in the active listing now
		const { data: active } = await borja
			.from('shopping_lists')
			.select('id')
			.eq('id', id)
			.is('deleted_at', null)
			.single();
		expect(active?.id).toBe(id);
	});

	it('T-11: guest (David) cannot restore', async () => {
		const id = await makeTrashedList();
		const david = await createClientAs(DAVID_ID);

		const { error } = await david.rpc('restore_list', { p_list_id: id });
		expect(error).not.toBeNull();
	});

	it('T-12: non-member (Eva) cannot restore', async () => {
		const id = await makeTrashedList();
		const eva = await createClientAs(EVA_ID);

		const { error } = await eva.rpc('restore_list', { p_list_id: id });
		expect(error).not.toBeNull();
	});

	it('T-13: member can hard-delete a soft-deleted list', async () => {
		const id = await makeTrashedList();
		const borja = await createClientAs(BORJA_ID);

		const { error } = await borja.rpc('hard_delete_list', { p_list_id: id });
		expect(error).toBeNull();

		const { data } = await admin.from('shopping_lists').select('id').eq('id', id);
		expect(data).toHaveLength(0);
		// Already gone — drop from cleanup list.
		const idx = trashedIds.indexOf(id);
		if (idx >= 0) trashedIds.splice(idx, 1);
	});

	it('T-14: hard delete on an active (non-trashed) list is rejected', async () => {
		const r = await sql(
			`INSERT INTO public.shopping_lists (collective_id, name, status, created_by)
			 VALUES ($1, 'Trash-RPC-guard', 'active', $2) RETURNING id`,
			[COLLECTIVE_ID, BORJA_ID]
		);
		const id = r.rows[0].id as string;
		trashedIds.push(id);

		const borja = await createClientAs(BORJA_ID);
		const { error } = await borja.rpc('hard_delete_list', { p_list_id: id });
		expect(error).not.toBeNull();

		// Row still present
		const { data } = await admin.from('shopping_lists').select('id').eq('id', id).single();
		expect(data?.id).toBe(id);
	});
});
