import type { SpreadsheetHistoryEntry } from '../types';

const DB_NAME = 'xk_spreadsheet_history';
const STORE_NAME = 'entries';
const DB_VERSION = 1;

function openDb(): Promise<IDBDatabase> {
  return new Promise((resolve, reject) => {
    const req = indexedDB.open(DB_NAME, DB_VERSION);
    req.onerror = () => reject(req.error);
    req.onsuccess = () => resolve(req.result);
    req.onupgradeneeded = () => {
      const db = req.result;
      if (!db.objectStoreNames.contains(STORE_NAME)) {
        const store = db.createObjectStore(STORE_NAME, { keyPath: 'id' });
        store.createIndex('tableName', 'tableName', { unique: false });
        store.createIndex('tableSheet', ['tableName', 'sheetKey'], {
          unique: false,
        });
        store.createIndex('createdAt', 'createdAt', { unique: false });
        store.createIndex('synced', 'synced', { unique: false });
      }
    };
  });
}

export async function appendLocalHistory(entry: SpreadsheetHistoryEntry) {
  const db = await openDb();
  return new Promise<void>((resolve, reject) => {
    const tx = db.transaction(STORE_NAME, 'readwrite');
    tx.objectStore(STORE_NAME).put(entry);
    tx.oncomplete = () => resolve();
    tx.onerror = () => reject(tx.error);
  });
}

export async function listLocalHistory(
  tableName: string,
  sheetKey?: string,
  limit = 100,
): Promise<SpreadsheetHistoryEntry[]> {
  const db = await openDb();
  return new Promise((resolve, reject) => {
    const tx = db.transaction(STORE_NAME, 'readonly');
    const store = tx.objectStore(STORE_NAME);
    const index = store.index('tableName');
    const req = index.getAll(tableName);
    req.onsuccess = () => {
      let items = (req.result as SpreadsheetHistoryEntry[]) ?? [];
      if (sheetKey) {
        items = items.filter((i) => i.sheetKey === sheetKey);
      }
      items.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
      resolve(items.slice(0, limit));
    };
    req.onerror = () => reject(req.error);
  });
}

export async function listUnsyncedHistory(): Promise<SpreadsheetHistoryEntry[]> {
  const db = await openDb();
  return new Promise((resolve, reject) => {
    const tx = db.transaction(STORE_NAME, 'readonly');
    const req = tx.objectStore(STORE_NAME).getAll();
    req.onsuccess = () => {
      const items = ((req.result as SpreadsheetHistoryEntry[]) ?? []).filter(
        (i) => !i.synced,
      );
      resolve(items);
    };
    req.onerror = () => reject(req.error);
  });
}

export async function markHistorySynced(ids: string[]) {
  if (!ids.length) return;
  const db = await openDb();
  const tx = db.transaction(STORE_NAME, 'readwrite');
  const store = tx.objectStore(STORE_NAME);
  for (const id of ids) {
    const getReq = store.get(id);
    getReq.onsuccess = () => {
      const entry = getReq.result as SpreadsheetHistoryEntry | undefined;
      if (entry) {
        entry.synced = true;
        store.put(entry);
      }
    };
  }
  await new Promise<void>((resolve, reject) => {
    tx.oncomplete = () => resolve();
    tx.onerror = () => reject(tx.error);
  });
}
