import { browser } from '$app/environment';
import { goto, invalidate } from '$app/navigation';
import { page } from '$app/state';
import { deleteLibrary } from '$lib/api';
import type { Library } from '$lib/schema';
import { getContext, setContext } from 'svelte';
import { toast } from 'svelte-sonner';

export class LibraryState {
	libraries = $state<Library[]>([]);
	activeLibrary = $state<Library | undefined>(undefined);
	createDialogOpen = $state(false);

	constructor(libraries: Library[]) {
		this.libraries = libraries;

		const activeLibrary = this.libraries.find((lib) => lib.id.toString() === page.params.libraryId);

		let previousLibrary: Library | undefined;

		if (browser) {
			previousLibrary = this.libraries.find(
				(lib) => lib.id.toString() === localStorage.getItem('previousLibraryId')
			);
		}

		this.activeLibrary = activeLibrary || previousLibrary || libraries[0];
	}

	async setActive(libraryId: number) {
		this.activeLibrary = this.libraries.find((lib) => lib.id === libraryId) || this.libraries[0];
		if (browser) {
			localStorage.setItem('previousLibraryId', this.activeLibrary.id.toString());
			await goto(`/library/${libraryId}/view`, { invalidate: ['app:libraries'] });
		}
	}

	updateLibraries(libraries: Library[]) {
		this.libraries = libraries;

		// Update the current library as it may have been removed
		if (!this.libraries.find((lib) => this.activeLibrary?.id === lib.id))
			this.activeLibrary = libraries[0] || undefined;
	}

	async deleteLibrary(libraryId: number) {
		// Store library with its original index
		const libIndex = this.libraries.findIndex((lib) => lib.id === libraryId);
		const deletionSnapshot = { library: this.libraries[libIndex], index: libIndex };

		// Optimistically delete the library
		this.libraries = this.libraries.filter((lib) => lib.id !== libraryId);

		try {
			// Delete library via API
			await deleteLibrary(libraryId);
			toast.success(`Deleted library '${deletionSnapshot.library}'`);
		} catch (err) {
			// Delete failed; restore library at its original position
			this.libraries.splice(deletionSnapshot.index, 0, deletionSnapshot.library);
			toast.error('Failed to delete library');
			console.error('Failed to delete library: ', err);
		}
	}

	addLibrary(library: Library) {
		this.libraries.push(library);
	}

	openLibraryCreateDialog() {
		this.createDialogOpen = true;
	}
}

const LIBRARY_KEY = Symbol('LIBRARY');

export function setLibraryState(libraries: Library[]) {
	return setContext(LIBRARY_KEY, new LibraryState(libraries));
}

export function getLibraryState() {
	return getContext<ReturnType<typeof setLibraryState>>(LIBRARY_KEY);
}
