/**
 * E-series: item_frequency RLS — read-only for members, trigger-only writes.
 * The table is populated exclusively by fn_record_item_frequency (SECURITY DEFINER trigger).
 * All direct INSERT/UPDATE/DELETE must be denied.
 */
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();

describe('item_frequency read access', () => {
	it('E-01: member (Borja) can read frequency suggestions', async () => {
		const borja = await createClientAs(BORJA_ID);
		const { data, error } = await borja
			.from('item_frequency')
			.select('name, use_count')
			.eq('collective_id', COLLECTIVE_ID)
			.order('use_count', { ascending: false })
			.limit(5);
		expect(error).toBeNull();
		expect(data!.length).toBeGreaterThanOrEqual(1);
	});

	it('E-02: guest (David) can read frequency suggestions', async () => {
		const david = await createClientAs(DAVID_ID);
		const { data, error } = await david
			.from('item_frequency')
			.select('name')
			.eq('collective_id', COLLECTIVE_ID);
		expect(error).toBeNull();
		expect(data!.length).toBeGreaterThanOrEqual(1);
	});

	it('E-03: Eva (non-member) sees no frequency data', async () => {
		const eva = await createClientAs(EVA_ID);
		const { data } = await eva
			.from('item_frequency')
			.select('name')
			.eq('collective_id', COLLECTIVE_ID);
		expect(data).toHaveLength(0);
	});

	it('E-04: prefix filter returns matching suggestions', async () => {
		const borja = await createClientAs(BORJA_ID);
		const { data, error } = await borja
			.from('item_frequency')
			.select('name')
			.eq('collective_id', COLLECTIVE_ID)
			.ilike('name', 'mi%');
		expect(error).toBeNull();
		// "milk" matches "mi%"
		expect(data!.some((row) => row.name === 'milk')).toBe(true);
	});
});

describe('item_frequency write protection', () => {
	it('E-05: member (Borja) cannot INSERT directly into item_frequency', async () => {
		const borja = await createClientAs(BORJA_ID);
		const { data, error } = await borja
			.from('item_frequency')
			.insert({ collective_id: COLLECTIVE_ID, name: 'hacked item', use_count: 999 })
			.select()
			.single();
		expect(data).toBeNull();
		expect(error).not.toBeNull();
	});

	it('E-06: admin (Ana) cannot UPDATE item_frequency directly', async () => {
		const ana = await createClientAs(ANA_ID);
		await ana
			.from('item_frequency')
			.update({ use_count: 999 })
			.eq('collective_id', COLLECTIVE_ID)
			.eq('name', 'milk');
		// Verify count was not changed
		const { data } = await admin
			.from('item_frequency')
			.select('use_count')
			.eq('collective_id', COLLECTIVE_ID)
			.eq('name', 'milk')
			.single();
		expect(data?.use_count).not.toBe(999);
	});

	it('E-07: member cannot DELETE from item_frequency', async () => {
		const borja = await createClientAs(BORJA_ID);
		await borja
			.from('item_frequency')
			.delete()
			.eq('collective_id', COLLECTIVE_ID)
			.eq('name', 'milk');
		// Verify "milk" still exists
		const { data } = await admin
			.from('item_frequency')
			.select('name')
			.eq('collective_id', COLLECTIVE_ID)
			.eq('name', 'milk')
			.single();
		expect(data?.name).toBe('milk');
	});
});

describe('item_frequency trigger — populated via INSERT on shopping_items', () => {
	let addedItemId: string;
	const TEST_ITEM_NAME = 'trigger-test-item-unique';
	let testListId: string;

	// Create a temporary list for this test group
	afterAll(async () => {
		if (addedItemId) {
			await admin.from('shopping_items').delete().eq('id', addedItemId);
		}
		if (testListId) {
			await admin.from('shopping_lists').delete().eq('id', testListId);
		}
		// Clean up the frequency record
		await admin
			.from('item_frequency')
			.delete()
			.eq('collective_id', COLLECTIVE_ID)
			.eq('name', TEST_ITEM_NAME.toLowerCase().trim());
	});

	it('E-08: adding an item increments item_frequency via trigger', async () => {
		// Get a list to add to
		const { data: lists } = await admin
			.from('shopping_lists')
			.select('id')
			.eq('collective_id', COLLECTIVE_ID)
			.is('deleted_at', null)
			.limit(1);

		// Use seed list or create one
		const listId = lists?.[0]?.id;
		if (!listId) {
			const { data: newList } = await admin
				.from('shopping_lists')
				.insert({ collective_id: COLLECTIVE_ID, name: 'Trigger test list', created_by: ANA_ID })
				.select('id')
				.single();
			testListId = newList!.id;
		}

		const useListId = listId ?? testListId;

		// Check before count
		const { data: before } = await admin
			.from('item_frequency')
			.select('use_count')
			.eq('collective_id', COLLECTIVE_ID)
			.eq('name', TEST_ITEM_NAME.toLowerCase())
			.maybeSingle();
		const beforeCount = before?.use_count ?? 0;

		// Insert an item (trigger fires)
		const ana = await createClientAs(ANA_ID);
		const { data: item, error } = await ana
			.from('shopping_items')
			.insert({ list_id: useListId, name: TEST_ITEM_NAME, sort_order: 999, created_by: ANA_ID })
			.select('id')
			.single();
		expect(error).toBeNull();
		addedItemId = item!.id;

		// Check after count
		const { data: after } = await admin
			.from('item_frequency')
			.select('use_count')
			.eq('collective_id', COLLECTIVE_ID)
			.eq('name', TEST_ITEM_NAME.toLowerCase())
			.single();
		expect(after?.use_count).toBe(beforeCount + 1);
	});
});
