/**
 * Storage Quota Management — monitors IndexedDB usage and evicts stale docs.
 *
 * Uses the Storage API (navigator.storage.estimate) to check quota,
 * and evicts documents not accessed in 30+ days via LRU policy.
 */

import type { DocumentId } from './document';

// ============================================================================
// TYPES
// ============================================================================

export interface StorageInfo {
	/** Bytes used */
	usage: number;
	/** Total quota in bytes */
	quota: number;
	/** Usage as a percentage (0–100) */
	percent: number;
	/** Whether persistent storage is granted */
	persisted: boolean;
}

// ============================================================================
// CONSTANTS
// ============================================================================

/** Warn the user when storage usage exceeds this percentage */
export const QUOTA_WARNING_PERCENT = 70;

/** Evict docs not accessed in this many milliseconds (30 days) */
const STALE_THRESHOLD_MS = 30 * 24 * 60 * 60 * 1000;

// ============================================================================
// PUBLIC API
// ============================================================================

/**
 * Get current storage usage info.
 */
export async function getStorageInfo(): Promise<StorageInfo> {
	if (!navigator.storage?.estimate) {
		return { usage: 0, quota: 0, percent: 0, persisted: false };
	}

	const [estimate, persisted] = await Promise.all([
		navigator.storage.estimate(),
		navigator.storage.persisted?.() ?? Promise.resolve(false),
	]);

	const usage = estimate.usage ?? 0;
	const quota = estimate.quota ?? 0;
	const percent = quota > 0 ? Math.round((usage / quota) * 100) : 0;

	return { usage, quota, percent, persisted };
}

/**
 * Request persistent storage so the browser won't evict our data under pressure.
 * Returns true if granted.
 */
export async function requestPersistentStorage(): Promise<boolean> {
	if (!navigator.storage?.persist) return false;
	return navigator.storage.persist();
}

/**
 * Evict stale documents from IndexedDB.
 * Removes docs whose `updatedAt` is older than 30 days.
 * Returns the list of evicted document IDs.
 */
export async function evictStaleDocs(dbName = 'rspace-docs'): Promise<DocumentId[]> {
	const evicted: DocumentId[] = [];
	const cutoff = Date.now() - STALE_THRESHOLD_MS;

	let db: IDBDatabase;
	try {
		db = await openDb(dbName);
	} catch {
		return evicted;
	}

	try {
		// Scan meta store for stale entries
		const staleIds = await new Promise<string[]>((resolve, reject) => {
			const tx = db.transaction('meta', 'readonly');
			const request = tx.objectStore('meta').openCursor();
			const ids: string[] = [];

			request.onsuccess = () => {
				const cursor = request.result;
				if (!cursor) { resolve(ids); return; }

				const meta = cursor.value as { docId: string; updatedAt: number };
				if (meta.updatedAt < cutoff) {
					ids.push(meta.docId);
				}
				cursor.continue();
			};
			request.onerror = () => reject(request.error);
		});

		// Delete stale docs + meta + sync states
		if (staleIds.length > 0) {
			const tx = db.transaction(['docs', 'meta', 'sync'], 'readwrite');
			const docsStore = tx.objectStore('docs');
			const metaStore = tx.objectStore('meta');

			for (const id of staleIds) {
				docsStore.delete(id);
				metaStore.delete(id);
				evicted.push(id as DocumentId);
			}

			// Clean sync states for evicted docs
			const syncStore = tx.objectStore('sync');
			const syncCursor = syncStore.openCursor();
			await new Promise<void>((resolve, reject) => {
				syncCursor.onsuccess = () => {
					const cursor = syncCursor.result;
					if (!cursor) { resolve(); return; }
					const key = cursor.key as string;
					if (staleIds.some(id => key.startsWith(`${id}\0`))) {
						cursor.delete();
					}
					cursor.continue();
				};
				syncCursor.onerror = () => reject(syncCursor.error);
			});

			await new Promise<void>((resolve, reject) => {
				tx.oncomplete = () => resolve();
				tx.onerror = () => reject(tx.error);
			});
		}
	} finally {
		db.close();
	}

	if (evicted.length > 0) {
		console.log(`[StorageQuota] Evicted ${evicted.length} stale documents`);
	}

	return evicted;
}

/**
 * Check if storage usage is above the warning threshold.
 */
export async function isQuotaWarning(): Promise<boolean> {
	const info = await getStorageInfo();
	return info.percent >= QUOTA_WARNING_PERCENT;
}

// ============================================================================
// HELPERS
// ============================================================================

function openDb(name: string): Promise<IDBDatabase> {
	return new Promise((resolve, reject) => {
		const request = indexedDB.open(name);
		request.onsuccess = () => resolve(request.result);
		request.onerror = () => reject(request.error);
	});
}
