import type {
	CompanionAssets,
	CompanionType,
	ForestElement,
	Progress,
	Settings,
	StyleReference,
} from "../types";

const DB_NAME = "zauberwald";
const DB_VERSION = 1;

export function openDB(name: string = DB_NAME): Promise<IDBDatabase> {
	return new Promise((resolve, reject) => {
		const request = indexedDB.open(name, DB_VERSION);
		request.onupgradeneeded = (event) => {
			const db = (event.target as IDBOpenDBRequest).result;
			if (!db.objectStoreNames.contains("progress")) {
				db.createObjectStore("progress", { keyPath: "id" });
			}
			if (!db.objectStoreNames.contains("companionAssets")) {
				db.createObjectStore("companionAssets", { keyPath: "characterType" });
			}
			if (!db.objectStoreNames.contains("styleReference")) {
				db.createObjectStore("styleReference", { keyPath: "id" });
			}
			if (!db.objectStoreNames.contains("forestElements")) {
				db.createObjectStore("forestElements", { keyPath: "id", autoIncrement: true });
			}
			if (!db.objectStoreNames.contains("settings")) {
				db.createObjectStore("settings", { keyPath: "id" });
			}
		};
		request.onsuccess = () => resolve(request.result);
		request.onerror = () => reject(request.error);
	});
}

export function getProgress(db: IDBDatabase): Promise<Progress | null> {
	return new Promise((resolve, reject) => {
		const tx = db.transaction("progress", "readonly");
		const store = tx.objectStore("progress");
		const request = store.get(1);
		request.onsuccess = () => resolve((request.result as Progress) ?? null);
		request.onerror = () => reject(request.error);
	});
}

export function saveProgress(db: IDBDatabase, progress: Progress): Promise<void> {
	return new Promise((resolve, reject) => {
		const tx = db.transaction("progress", "readwrite");
		const store = tx.objectStore("progress");
		const request = store.put(progress);
		request.onsuccess = () => resolve();
		request.onerror = () => reject(request.error);
	});
}

export function getSettings(db: IDBDatabase): Promise<Settings | null> {
	return new Promise((resolve, reject) => {
		const tx = db.transaction("settings", "readonly");
		const store = tx.objectStore("settings");
		const request = store.get(1);
		request.onsuccess = () => resolve((request.result as Settings) ?? null);
		request.onerror = () => reject(request.error);
	});
}

export function saveSettings(db: IDBDatabase, settings: Settings): Promise<void> {
	return new Promise((resolve, reject) => {
		const tx = db.transaction("settings", "readwrite");
		const store = tx.objectStore("settings");
		const request = store.put(settings);
		request.onsuccess = () => resolve();
		request.onerror = () => reject(request.error);
	});
}

export function saveCompanionAssets(db: IDBDatabase, assets: CompanionAssets): Promise<void> {
	return new Promise((resolve, reject) => {
		const tx = db.transaction("companionAssets", "readwrite");
		const store = tx.objectStore("companionAssets");
		const request = store.put(assets);
		request.onsuccess = () => resolve();
		request.onerror = () => reject(request.error);
	});
}

export function getCompanionAssets(db: IDBDatabase, characterType: CompanionType): Promise<CompanionAssets | null> {
	return new Promise((resolve, reject) => {
		const tx = db.transaction("companionAssets", "readonly");
		const store = tx.objectStore("companionAssets");
		const request = store.get(characterType);
		request.onsuccess = () => resolve((request.result as CompanionAssets) ?? null);
		request.onerror = () => reject(request.error);
	});
}

export function saveStyleReference(db: IDBDatabase, ref: StyleReference): Promise<void> {
	return new Promise((resolve, reject) => {
		const tx = db.transaction("styleReference", "readwrite");
		const store = tx.objectStore("styleReference");
		const request = store.put(ref);
		request.onsuccess = () => resolve();
		request.onerror = () => reject(request.error);
	});
}

export function getStyleReference(db: IDBDatabase): Promise<StyleReference | null> {
	return new Promise((resolve, reject) => {
		const tx = db.transaction("styleReference", "readonly");
		const store = tx.objectStore("styleReference");
		const request = store.get(1);
		request.onsuccess = () => resolve((request.result as StyleReference) ?? null);
		request.onerror = () => reject(request.error);
	});
}

export function saveForestElement(db: IDBDatabase, element: ForestElement): Promise<number> {
	return new Promise((resolve, reject) => {
		const tx = db.transaction("forestElements", "readwrite");
		const store = tx.objectStore("forestElements");
		const request = store.add(element);
		request.onsuccess = () => resolve(request.result as number);
		request.onerror = () => reject(request.error);
	});
}

export function getForestElements(db: IDBDatabase): Promise<ForestElement[]> {
	return new Promise((resolve, reject) => {
		const tx = db.transaction("forestElements", "readonly");
		const store = tx.objectStore("forestElements");
		const request = store.getAll();
		request.onsuccess = () => resolve((request.result as ForestElement[]) ?? []);
		request.onerror = () => reject(request.error);
	});
}
