const TTL_MS = 24 * 60 * 60 * 1000;

type Progress = { stepId: string; version: number; updatedAt: number };

const memory = new Map<string, string>();

function read(key: string): string | null {
	try {
		return localStorage.getItem(key) ?? memory.get(key) ?? null;
	} catch {
		return memory.get(key) ?? null;
	}
}

function write(key: string, value: string): void {
	memory.set(key, value);
	try {
		localStorage.setItem(key, value);
	} catch {
		// Private mode or quota: memory fallback is enough for this page.
	}
}

function remove(key: string): void {
	memory.delete(key);
	try {
		localStorage.removeItem(key);
	} catch {
		// ignore
	}
}

export function progressKey(publicKey: string, tourId: string): string {
	return `circuy:${publicKey}:${tourId}`;
}

export function seenKey(publicKey: string): string {
	return `circuy:${publicKey}:seen`;
}

export function sessionKey(publicKey: string): string {
	return `circuy:${publicKey}:sid`;
}

export function readProgress(
	publicKey: string,
	tourId: string,
	version: number,
	now = Date.now(),
): string | null {
	const raw = read(progressKey(publicKey, tourId));
	if (!raw) return null;
	try {
		const parsed = JSON.parse(raw) as Progress;
		if (now - parsed.updatedAt > TTL_MS || parsed.version !== version) {
			remove(progressKey(publicKey, tourId));
			return null;
		}
		return parsed.stepId;
	} catch {
		remove(progressKey(publicKey, tourId));
		return null;
	}
}

export function writeProgress(
	publicKey: string,
	tourId: string,
	version: number,
	stepId: string,
	now = Date.now(),
): void {
	write(
		progressKey(publicKey, tourId),
		JSON.stringify({ stepId, version, updatedAt: now } satisfies Progress),
	);
}

export function clearProgress(publicKey: string, tourId: string): void {
	remove(progressKey(publicKey, tourId));
}

export function readSeen(publicKey: string): string[] {
	const raw = read(seenKey(publicKey));
	if (!raw) return [];
	try {
		const parsed = JSON.parse(raw) as unknown;
		return Array.isArray(parsed)
			? parsed.filter((id) => typeof id === "string")
			: [];
	} catch {
		return [];
	}
}

export function markSeen(publicKey: string, tourId: string): void {
	const seen = new Set(readSeen(publicKey));
	seen.add(tourId);
	write(seenKey(publicKey), JSON.stringify([...seen]));
	clearProgress(publicKey, tourId);
}

export function sessionId(publicKey: string): string {
	const key = sessionKey(publicKey);
	try {
		const existing = sessionStorage.getItem(key);
		if (existing) return existing;
		const created = crypto.randomUUID();
		sessionStorage.setItem(key, created);
		return created;
	} catch {
		return crypto.randomUUID();
	}
}

export { TTL_MS };
