import { writable } from 'svelte/store';
import { getSupabase } from '$lib/supabase';
import { generateId } from '$lib/utils/id';
import type { ShoppingList, ShoppingItem, ItemFrequency } from '@colectivo/types';

// ── Global list store (overview page) ─────────────────────────────────────────

export const lists = writable<ShoppingList[]>([]);
export const listsLoading = writable(false);

export async function loadLists(collectiveId: string) {
	listsLoading.set(true);
	const { data, error } = await getSupabase()
		.from('shopping_lists')
		.select('*')
		.eq('collective_id', collectiveId)
		.is('deleted_at', null)
		.order('created_at', { ascending: false });

	if (!error && data) {
		lists.set(data as ShoppingList[]);
	}
	listsLoading.set(false);
}

export async function loadTrashedLists(collectiveId: string): Promise<ShoppingList[]> {
	const { data, error } = await getSupabase()
		.from('shopping_lists')
		.select('*')
		.eq('collective_id', collectiveId)
		.not('deleted_at', 'is', null)
		.order('deleted_at', { ascending: false });

	if (error || !data) return [];
	return data as ShoppingList[];
}

// ── List mutations (optimistic) ───────────────────────────────────────────────

export async function createList(
	collectiveId: string,
	name: string,
	userId: string
): Promise<ShoppingList | null> {
	const tempId = generateId();
	const optimistic: ShoppingList = {
		id: tempId,
		collective_id: collectiveId,
		name,
		status: 'active',
		created_by: userId,
		created_at: new Date().toISOString(),
		completed_at: null,
		deleted_at: null
	};
	lists.update((ls) => [optimistic, ...ls]);

	const { data, error } = await getSupabase()
		.from('shopping_lists')
		.insert({ collective_id: collectiveId, name, created_by: userId })
		.select()
		.single();

	if (error || !data) {
		lists.update((ls) => ls.filter((l) => l.id !== tempId));
		return null;
	}

	const real = data as ShoppingList;
	lists.update((ls) => ls.map((l) => (l.id === tempId ? real : l)));
	return real;
}

export async function renameList(id: string, name: string) {
	lists.update((ls) => ls.map((l) => (l.id === id ? { ...l, name } : l)));
	await getSupabase().from('shopping_lists').update({ name }).eq('id', id);
}

export async function softDeleteList(id: string) {
	lists.update((ls) => ls.filter((l) => l.id !== id));
	await getSupabase()
		.from('shopping_lists')
		.update({ deleted_at: new Date().toISOString() })
		.eq('id', id);
}

export async function restoreList(id: string, collectiveId: string) {
	await getSupabase().from('shopping_lists').update({ deleted_at: null }).eq('id', id);
	await loadLists(collectiveId);
}

export async function permanentDeleteList(id: string) {
	await getSupabase().from('shopping_lists').delete().eq('id', id);
}

export async function archiveList(id: string) {
	lists.update((ls) => ls.filter((l) => l.id !== id));
	await getSupabase().from('shopping_lists').update({ status: 'archived' }).eq('id', id);
}

export async function completeList(id: string) {
	const completed_at = new Date().toISOString();
	lists.update((ls) =>
		ls.map((l) => (l.id === id ? { ...l, status: 'completed' as const, completed_at } : l))
	);
	await getSupabase()
		.from('shopping_lists')
		.update({ status: 'completed', completed_at })
		.eq('id', id);
}

export async function resetList(id: string) {
	lists.update((ls) =>
		ls.map((l) =>
			l.id === id ? { ...l, status: 'active' as const, completed_at: null } : l
		)
	);
	await Promise.all([
		getSupabase()
			.from('shopping_lists')
			.update({ status: 'active', completed_at: null })
			.eq('id', id),
		getSupabase()
			.from('shopping_items')
			.update({ is_checked: false, checked_by: null, checked_at: null })
			.eq('list_id', id)
	]);
}

// ── Item operations (used by [id] page) ───────────────────────────────────────

export async function loadItems(listId: string): Promise<ShoppingItem[]> {
	const { data, error } = await getSupabase()
		.from('shopping_items')
		.select('*')
		.eq('list_id', listId)
		.order('sort_order', { ascending: true });

	if (error || !data) return [];
	return data as ShoppingItem[];
}

/**
 * Insert a new item. Accepts an optional pre-generated `id` so callers can
 * use the same UUID as their local optimistic row — this makes the write
 * idempotent: if the INSERT succeeds on the server but the response is lost
 * (e.g. network blip, Playwright setOffline), retrying with the same id
 * returns a 409 PK conflict that the client treats as "already there".
 */
export async function addItem(
	listId: string,
	name: string,
	quantity: number | null,
	userId: string,
	sortOrder: number,
	id?: string
): Promise<ShoppingItem | null> {
	const payload = {
		...(id ? { id } : {}),
		list_id: listId,
		name,
		quantity,
		sort_order: sortOrder,
		created_by: userId
	};

	const { data, error } = await getSupabase()
		.from('shopping_items')
		.insert(payload)
		.select()
		.single();

	if (error || !data) return null;
	return data as ShoppingItem;
}

export async function updateItem(
	id: string,
	patch: Partial<
		Pick<
			ShoppingItem,
			'name' | 'quantity' | 'is_checked' | 'checked_by' | 'checked_at' | 'sort_order'
		>
	>
) {
	await getSupabase().from('shopping_items').update(patch).eq('id', id);
}

export async function checkItem(id: string, userId: string, checked: boolean) {
	const patch = checked
		? { is_checked: true, checked_by: userId, checked_at: new Date().toISOString() }
		: { is_checked: false, checked_by: null, checked_at: null };
	await getSupabase().from('shopping_items').update(patch).eq('id', id);
}

export async function deleteItem(id: string) {
	await getSupabase().from('shopping_items').delete().eq('id', id);
}

// ── Bulk operations (selection mode) ──────────────────────────────────────────

export async function bulkDeleteItems(ids: string[]): Promise<void> {
	if (!ids.length) return;
	await getSupabase().from('shopping_items').delete().in('id', ids);
}

export async function bulkMoveItems(ids: string[], newListId: string): Promise<void> {
	if (!ids.length) return;
	await getSupabase().from('shopping_items').update({ list_id: newListId }).in('id', ids);
}

export async function bulkCheckItems(ids: string[], userId: string): Promise<void> {
	if (!ids.length) return;
	await getSupabase()
		.from('shopping_items')
		.update({ is_checked: true, checked_by: userId, checked_at: new Date().toISOString() })
		.in('id', ids)
		.eq('is_checked', false);
}

export async function reorderItems(items: Pick<ShoppingItem, 'id'>[]) {
	await Promise.all(
		items.map((item, index) =>
			getSupabase().from('shopping_items').update({ sort_order: index }).eq('id', item.id)
		)
	);
}

// ── Suggestions (item_frequency) ──────────────────────────────────────────────

export async function fetchSuggestions(
	collectiveId: string,
	prefix: string
): Promise<ItemFrequency[]> {
	if (!prefix.trim()) {
		const { data } = await getSupabase()
			.from('item_frequency')
			.select('*')
			.eq('collective_id', collectiveId)
			.order('use_count', { ascending: false })
			.limit(5);
		return (data as ItemFrequency[]) ?? [];
	}

	const { data } = await getSupabase()
		.from('item_frequency')
		.select('*')
		.eq('collective_id', collectiveId)
		.ilike('name', `${prefix.toLowerCase().trim()}%`)
		.order('use_count', { ascending: false })
		.limit(10);
	return (data as ItemFrequency[]) ?? [];
}
