import { db } from '@/lib/db/db';
import { downloadJson } from './file';

const TABLES = [
  'campaigns', 'characters', 'encounters', 'diceRolls',
  'notes', 'npcs', 'quests', 'calendars', 'maps', 'homebrew',
] as const;

const FORMAT = 'ttrpg-manager:backup';

export class BackupError extends Error {}

/** Snapshot every table into a portable object. */
export async function buildBackup(): Promise<{ format: string; version: number; data: Record<string, unknown[]> }> {
  const data: Record<string, unknown[]> = {};
  for (const t of TABLES) data[t] = await db.table(t).toArray();
  return { format: FORMAT, version: 1, data };
}

/** Download a full backup of all campaigns and data. */
export async function exportBackup(): Promise<void> {
  downloadJson('ttrpg-manager-backup.json', await buildBackup());
}

/**
 * Restore a backup, REPLACING all current data. Runs in one transaction so a
 * failure rolls back cleanly.
 */
export async function restoreBackup(text: string): Promise<void> {
  let parsed: unknown;
  try {
    parsed = JSON.parse(text);
  } catch {
    throw new BackupError('That file is not valid JSON.');
  }
  const data = (parsed as { data?: Record<string, unknown[]> })?.data;
  if (!data || typeof data !== 'object') throw new BackupError('That file is not a TTRPG Manager backup.');

  await db.transaction('rw', TABLES.map((t) => db.table(t)), async () => {
    for (const t of TABLES) {
      await db.table(t).clear();
      const rows = data[t];
      if (Array.isArray(rows) && rows.length) await db.table(t).bulkAdd(rows);
    }
  });
}

/** Wipe all data (danger zone). */
export async function clearAllData(): Promise<void> {
  await db.transaction('rw', TABLES.map((t) => db.table(t)), async () => {
    for (const t of TABLES) await db.table(t).clear();
  });
}
