/**
 * DB helpers for Fase 7 E2E tests — direct-to-postgres helpers that bypass RLS
 * via the admin client. Import from `*.test.ts` only, never from `src/`.
 *
 * These helpers exist because Fase 7 exercises collective creation end-to-end:
 * tests need to reset the "Eva has no collective" precondition between runs
 * and seed invitation rows in exotic states (expired / already-accepted) that
 * the UI can't produce on its own.
 */
import { sql, ANA_ID, COLLECTIVE_ID } from '@colectivo/test-utils';

/**
 * Scrub all state created by Eva and all memberships she holds.
 *
 * Call in `beforeEach` of suites that assume Eva is a non-member at start.
 * Implementation via raw SQL (bypasses RLS + cascades) instead of admin client
 * to avoid a two-step delete dance.
 */
export async function resetEva(): Promise<void> {
	const EVA_ID = '55555555-5555-5555-5555-555555555555';
	// Delete collectives Eva created (CASCADE wipes members + invitations + lists).
	await sql('DELETE FROM public.collectives WHERE created_by = $1', [EVA_ID]);
	// Clear any memberships Eva holds in other collectives.
	await sql('DELETE FROM public.collective_members WHERE user_id = $1', [EVA_ID]);
	// Clear any invitations that *targeted* Eva (accepted_by).
	await sql(
		'UPDATE public.collective_invitations SET accepted_at = NULL, accepted_by = NULL WHERE accepted_by = $1',
		[EVA_ID]
	);
}

/**
 * Insert an invitation row with an expires_at in the past.
 * Returns the token (uuid).
 */
export async function seedExpiredInvitation(
	collectiveId: string = COLLECTIVE_ID,
	createdBy: string = ANA_ID
): Promise<string> {
	const res = await sql(
		`INSERT INTO public.collective_invitations (collective_id, role, created_by, expires_at)
		 VALUES ($1, 'member', $2, now() - interval '1 hour')
		 RETURNING token`,
		[collectiveId, createdBy]
	);
	return res.rows[0].token as string;
}

/**
 * Insert an invitation row already marked accepted (accepted_at + accepted_by).
 * Returns the token.
 */
export async function seedUsedInvitation(
	collectiveId: string = COLLECTIVE_ID,
	createdBy: string = ANA_ID,
	acceptedBy: string = ANA_ID
): Promise<string> {
	const res = await sql(
		`INSERT INTO public.collective_invitations (collective_id, role, created_by, accepted_at, accepted_by)
		 VALUES ($1, 'member', $2, now(), $3)
		 RETURNING token`,
		[collectiveId, createdBy, acceptedBy]
	);
	return res.rows[0].token as string;
}

/**
 * Reset the seed collective's membership roster back to the post-seed state:
 *   Ana = admin, Borja = member, Carmen = member, David = guest
 *
 * Call in `afterAll` of suites that mutate roles / remove members. Critical —
 * downstream suites (lists, items, tasks, notes) assume this shape.
 */
export async function restoreSeedMembership(): Promise<void> {
	// Use raw SQL to bypass RLS without needing the service-role JWT (which
	// isn't always exported to the Playwright process env).
	const seed = [
		['11111111-1111-1111-1111-111111111111', 'admin'],
		['22222222-2222-2222-2222-222222222222', 'member'],
		['33333333-3333-3333-3333-333333333333', 'member'],
		['44444444-4444-4444-4444-444444444444', 'guest']
	] as const;

	for (const [userId, role] of seed) {
		await sql(
			`INSERT INTO public.collective_members (collective_id, user_id, role)
			 VALUES ($1, $2, $3::public.member_role)
			 ON CONFLICT (collective_id, user_id) DO UPDATE SET role = EXCLUDED.role`,
			[COLLECTIVE_ID, userId, role]
		);
	}

	// Rename the collective back if a test changed it. Emoji stays whatever.
	await sql('UPDATE public.collectives SET name = $1 WHERE id = $2', [
		'Casa García-López',
		COLLECTIVE_ID
	]);

	// Nuke any invitations that accumulated.
	await sql('DELETE FROM public.collective_invitations WHERE collective_id = $1', [COLLECTIVE_ID]);
}

/** Count rows in collective_members for a given (collective, user). 0 or 1. */
export async function countMembership(collectiveId: string, userId: string): Promise<number> {
	const res = await sql(
		'SELECT count(*)::int AS n FROM public.collective_members WHERE collective_id = $1 AND user_id = $2',
		[collectiveId, userId]
	);
	return res.rows[0].n as number;
}
