import { beforeEach, describe, expect, it, vi } from 'vitest';

// backup-panel.ts only imports { sendMessage } from '../../shared/state'.
// We provide the full shared/state surface so TypeScript is satisfied.
vi.mock('../../../shared/state', () => ({
  sendMessage: vi.fn(),
  openVaultTab: vi.fn(),
  registerHost: vi.fn(),
  getState: vi.fn(),
  setState: vi.fn(),
  navigate: vi.fn(),
  escapeHtml: (s: string) => s,
  popOutToTab: vi.fn(),
  isInTab: vi.fn(() => false),
}));

import { sendMessage } from '../../../shared/state';
import { renderBackupPanel, teardown } from '../backup-panel';

const mockSendMessage = sendMessage as ReturnType<typeof vi.fn>;

describe('backup panel — export', () => {
  let app: HTMLElement;

  beforeEach(() => {
    mockSendMessage.mockReset();
    teardown();
    document.body.innerHTML = '<div id="app"></div>';
    app = document.getElementById('app')!;
  });

  it('clicking export with no passphrase is a no-op', async () => {
    renderBackupPanel(app);
    vi.spyOn(window, 'prompt').mockReturnValue(null);

    (app.querySelector('#export-btn') as HTMLButtonElement).click();
    await new Promise((r) => setTimeout(r, 0));

    expect(mockSendMessage).not.toHaveBeenCalled();
  });

  it('clicking export with a passphrase fires export_backup', async () => {
    renderBackupPanel(app);
    vi.spyOn(window, 'prompt').mockReturnValue('test-backup-pass');
    mockSendMessage.mockResolvedValue({ ok: true, data: { bytes: new ArrayBuffer(123) } });

    (app.querySelector('#include-image') as HTMLInputElement).checked = true;
    (app.querySelector('#export-btn') as HTMLButtonElement).click();
    await new Promise((r) => setTimeout(r, 50));

    expect(mockSendMessage).toHaveBeenCalledWith({
      type: 'export_backup',
      passphrase: 'test-backup-pass',
      includeImage: true,
    });
  });

  it('export error surfaces in the status pre', async () => {
    renderBackupPanel(app);
    vi.spyOn(window, 'prompt').mockReturnValue('p');
    mockSendMessage.mockResolvedValue({ ok: false, error: 'no reference image stored locally' });

    (app.querySelector('#export-btn') as HTMLButtonElement).click();
    await new Promise((r) => setTimeout(r, 50));

    const status = app.querySelector('#export-status') as HTMLElement;
    expect(status.textContent).toContain('Failed');
    expect(status.textContent).toContain('no reference image');
  });
});

describe('backup panel — restore', () => {
  let app: HTMLElement;

  beforeEach(() => {
    mockSendMessage.mockReset();
    teardown();
    document.body.innerHTML = '<div id="app"></div>';
    app = document.getElementById('app')!;
  });

  it('clicking restore without filling new-remote shows an error', async () => {
    renderBackupPanel(app);
    vi.spyOn(window, 'prompt').mockReturnValue('p');

    // Simulate file picked — this reveals the fieldset with the restore button.
    const fakeFile = new File([new Uint8Array([0x52, 0x42, 0x41, 0x4b, 0x01])], 'v.relbak');
    const input = app.querySelector('#restore-file') as HTMLInputElement;
    Object.defineProperty(input, 'files', { value: [fakeFile] });
    input.dispatchEvent(new Event('change'));

    (app.querySelector('#restore-btn') as HTMLButtonElement).click();
    await new Promise((r) => setTimeout(r, 50));

    const status = app.querySelector('#restore-status') as HTMLElement;
    expect(status.textContent).toContain('fill in');
    expect(mockSendMessage).not.toHaveBeenCalled();
  });
});
