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

vi.mock('../../../../shared/state', async () => {
  const navigate = vi.fn();
  const setState = vi.fn();
  const sendMessage = vi.fn();
  const getState = vi.fn(() => ({
    view: 'add', entries: [], selectedId: null, selectedItem: null, selectedIndex: 0,
    searchQuery: '', activeGroup: null, error: null, loading: false,
    capturedTabId: null, capturedUrl: '', newType: 'totp',
  }));
  const escapeHtml = (s: string) => s
    .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;').replace(/'/g, '&#39;');
  return { navigate, setState, sendMessage, getState, escapeHtml, popOutToTab: vi.fn(), isInTab: vi.fn(() => false), openVaultTab: vi.fn() };
});

import { renderForm } from '../totp';
import { sendMessage } from '../../../../shared/state';
import { base32Decode } from '../../../../shared/base32';

describe('Totp save shape', () => {
  beforeEach(() => {
    document.body.innerHTML = '<div id="app"></div>';
    vi.mocked(sendMessage).mockReset();
    vi.mocked(sendMessage).mockResolvedValue({ ok: true, data: { id: 'fakeid0000000000', items: [] } });
  });

  it('TOTP kind: secret round-trips via base32, defaults applied', async () => {
    const app = document.getElementById('app')!;
    renderForm(app, 'add', null);

    (document.getElementById('f-title') as HTMLInputElement).value = 'GitHub';
    (document.getElementById('f-secret') as HTMLInputElement).value = 'JBSWY3DPEHPK3PXP';
    (document.getElementById('f-issuer') as HTMLInputElement).value = 'GitHub';
    (document.getElementById('f-label') as HTMLInputElement).value = 'alice';

    document.getElementById('save-btn')!.click();
    await new Promise(r => setTimeout(r, 5));

    const calls = vi.mocked(sendMessage).mock.calls;
    const addCall = calls.find(([msg]) => (msg as { type: string }).type === 'add_item');
    const msg = addCall![0] as { type: 'add_item'; item: any };
    expect(msg.item.type).toBe('totp');
    expect(msg.item.core).toMatchObject({
      type: 'totp',
      issuer: 'GitHub',
      label: 'alice',
      config: {
        secret: Array.from(base32Decode('JBSWY3DPEHPK3PXP')),
        algorithm: 'sha1',
        digits: 6,
        period_seconds: 30,
        kind: 'totp',
      },
    });
  });

  it('Steam kind: digits set to 5, kind set to steam', async () => {
    const app = document.getElementById('app')!;
    renderForm(app, 'add', null);

    (document.getElementById('f-title') as HTMLInputElement).value = 'Steam';
    (document.getElementById('f-secret') as HTMLInputElement).value = 'JBSWY3DPEHPK3PXP';
    (document.getElementById('kind-steam') as HTMLButtonElement).click();
    // After the click, the form re-renders; re-query the secret field and re-populate.
    (document.getElementById('f-secret') as HTMLInputElement).value = 'JBSWY3DPEHPK3PXP';
    (document.getElementById('f-title') as HTMLInputElement).value = 'Steam';

    document.getElementById('save-btn')!.click();
    await new Promise(r => setTimeout(r, 5));

    const calls = vi.mocked(sendMessage).mock.calls;
    const addCall = calls.find(([msg]) => (msg as { type: string }).type === 'add_item');
    const msg = addCall![0] as { type: 'add_item'; item: any };
    expect(msg.item.core.config).toMatchObject({
      digits: 5,
      kind: 'steam',
      algorithm: 'sha1',
      period_seconds: 30,
    });
  });

  it('rejects empty secret', async () => {
    const app = document.getElementById('app')!;
    renderForm(app, 'add', null);
    (document.getElementById('f-title') as HTMLInputElement).value = 'no secret';
    document.getElementById('save-btn')!.click();
    await new Promise(r => setTimeout(r, 5));

    const calls = vi.mocked(sendMessage).mock.calls;
    const addCall = calls.find(([msg]) => (msg as { type: string }).type === 'add_item');
    expect(addCall).toBeUndefined();
  });
});
