const DB_NAME = 'initiative-draft';
const STORE = 'files';

function openDb(): Promise<IDBDatabase> {
  return new Promise((resolve, reject) => {
    const req = indexedDB.open(DB_NAME, 1);
    req.onupgradeneeded = () => {
      if (!req.result.objectStoreNames.contains(STORE)) {
        req.result.createObjectStore(STORE);
      }
    };
    req.onsuccess = () => resolve(req.result);
    req.onerror = () => reject(req.error);
  });
}

async function withStore<T>(
  mode: IDBTransactionMode,
  fn: (s: IDBObjectStore) => IDBRequest<T>,
): Promise<T> {
  const db = await openDb();
  return new Promise<T>((resolve, reject) => {
    const tx = db.transaction(STORE, mode);
    const req = fn(tx.objectStore(STORE));
    req.onsuccess = () => resolve(req.result as T);
    req.onerror = () => reject(req.error);
  });
}

export const fileStore = {
  put: (key: string, blob: Blob) => withStore('readwrite', (s) => s.put(blob, key)),
  get: (key: string) => withStore<Blob | undefined>('readonly', (s) => s.get(key)),
  del: (key: string) => withStore('readwrite', (s) => s.delete(key)),
  clearPrefix: async (prefix: string) => {
    const db = await openDb();
    await new Promise<void>((resolve, reject) => {
      const tx = db.transaction(STORE, 'readwrite');
      const store = tx.objectStore(STORE);
      const r = store.getAllKeys();
      r.onsuccess = () => {
        const keys = (r.result as IDBValidKey[]).filter(
          (k) => typeof k === 'string' && k.startsWith(prefix),
        );
        for (const k of keys) store.delete(k);
      };
      r.onerror = () => reject(r.error);
      tx.oncomplete = () => resolve();
      tx.onerror = () => reject(tx.error);
    });
  },
};

export const snapshotStore = {
  load<T>(key: string): T | null {
    try {
      const raw = localStorage.getItem(key);
      return raw ? (JSON.parse(raw) as T) : null;
    } catch {
      return null;
    }
  },
  save<T>(key: string, value: T) {
    localStorage.setItem(key, JSON.stringify(value));
  },
  clear(key: string) {
    localStorage.removeItem(key);
  },
};
