import { describe, it, expect, beforeEach } from 'vitest';
import { db } from '@/lib/db/db';
import { campaignsRepo, charactersRepo, notesRepo } from '@/lib/db/repositories';
import { buildBackup, restoreBackup, clearAllData } from './backup';

beforeEach(async () => {
  await db.delete();
  await db.open();
});

describe('backup round-trip', () => {
  it('exports all data and restores it after a wipe', async () => {
    const c = await campaignsRepo.create({ name: 'Backed Up', system: '5e', description: '' });
    await charactersRepo.create(c.id, { system: '5e', name: 'Saved Hero', kind: 'pc', ancestry: '', className: '', level: 2 });
    await notesRepo.create(c.id, 'Saved Note');

    const backup = await buildBackup();
    await clearAllData();
    expect(await campaignsRepo.list()).toHaveLength(0);

    await restoreBackup(JSON.stringify(backup));
    const campaigns = await campaignsRepo.list();
    expect(campaigns).toHaveLength(1);
    expect(campaigns[0]!.name).toBe('Backed Up');
    expect(await charactersRepo.listByCampaign(c.id)).toHaveLength(1);
    expect(await notesRepo.listByCampaign(c.id)).toHaveLength(1);
  });

  it('rejects a non-backup file', async () => {
    await expect(restoreBackup('{"foo":1}')).rejects.toThrow();
    await expect(restoreBackup('not json')).rejects.toThrow();
  });

  it('backfills new fields on a character from an older backup (no missing-field crash)', async () => {
    const c = await campaignsRepo.create({ name: 'Old Save', system: '5e', description: '' });
    // Simulate a pre-v15 character row: no feats/concentration/equippedArmor.
    const legacy = {
      format: 'ttrpg-manager:backup', version: 1,
      data: {
        campaigns: [{ id: c.id, name: 'Old Save', system: '5e', description: '', createdAt: 't', updatedAt: 't' }],
        characters: [{
          id: 'old1', campaignId: c.id, system: '5e', kind: 'pc', name: 'Legacy', ancestry: '', className: 'Fighter', level: 3,
          abilities: { str: 14, dex: 12, con: 13, int: 10, wis: 11, cha: 9 }, hp: { current: 20, max: 20, temp: 0 },
          speed: 30, armorBonus: 0, skillRanks: {}, saveRanks: {}, perceptionRank: 'trained', notes: '', createdAt: 't', updatedAt: 't',
        }],
      },
    };
    await clearAllData();
    await restoreBackup(JSON.stringify(legacy));
    const [restored] = await charactersRepo.listByCampaign(c.id);
    expect(restored!.name).toBe('Legacy');
    // The fields the sheet reads must exist (default-backfilled), not be undefined.
    expect(restored!.feats).toEqual([]);
    expect(restored!.concentration).toBeNull();
    expect(restored!.spellcasting.spells).toEqual([]);
  });
});
