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

vi.mock('../../../shared/state', async () => {
  const escapeHtml = (s: string) => s
    .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;').replace(/'/g, '&#39;');
  return { escapeHtml, popOutToTab: vi.fn(), isInTab: vi.fn(() => false), openVaultTab: vi.fn() };
});

import {
  renderRow,
  renderConcealedRow,
  renderSignatureBlock,
  wireFieldHandlers,
} from '../fields';

describe('renderRow', () => {
  it('plain row contains label + value', () => {
    const html = renderRow({ label: 'username', value: 'alice' });
    expect(html).toContain('username');
    expect(html).toContain('alice');
    expect(html).toContain('field-row');
  });

  it('copyable row exposes a copy action', () => {
    const html = renderRow({ label: 'email', value: 'alice@example.com', copyable: true });
    expect(html).toContain('data-field-action="copy"');
  });

  it('href row wraps value in an external anchor', () => {
    const html = renderRow({ label: 'url', value: 'https://example.com', href: 'https://example.com' });
    expect(html).toContain('href="https://example.com"');
    expect(html).toContain('target="_blank"');
    expect(html).toContain('rel="noopener noreferrer"');
  });

  it('monospace flag toggles the monospace class', () => {
    const html = renderRow({ label: 'fingerprint', value: 'AB:CD', monospace: true });
    expect(html).toContain('monospace');
  });

  it('multiline value renders inside a <pre>', () => {
    const html = renderRow({ label: 'address', value: '1 Main\n2 Main', multiline: true });
    expect(html).toContain('<pre');
  });

  it('escapes HTML in value and label', () => {
    const html = renderRow({ label: '<script>x</script>', value: '"&<>' });
    expect(html).not.toContain('<script>');
    expect(html).toContain('&amp;');
    expect(html).toContain('&lt;');
  });
});

describe('renderConcealedRow', () => {
  it('initial state hides the value behind a placeholder', () => {
    const html = renderConcealedRow({ id: 'pw1', label: 'password', value: 'hunter2' });
    expect(html).toContain('data-field-id="pw1"');
    expect(html).toContain('data-revealed="false"');
    expect(html).toContain('••••');
    // Plaintext is in a data attribute on the row, NOT in the visible textContent.
    expect(html).not.toMatch(/>hunter2</);
  });

  it('exposes show + copy actions', () => {
    const html = renderConcealedRow({ id: 'pw1', label: 'password', value: 'hunter2' });
    expect(html).toContain('data-field-action="reveal"');
    expect(html).toContain('data-field-action="copy"');
  });

  it('multiline concealed shows char count when hidden', () => {
    const html = renderConcealedRow({ id: 'k1', label: 'key', value: 'abcdefghij', multiline: true });
    expect(html).toContain('•••• (10 chars)');
  });
});

describe('renderSignatureBlock', () => {
  it('default accent is gold', () => {
    const html = renderSignatureBlock({ children: '<p>hi</p>' });
    expect(html).toContain('sig-block--gold');
    expect(html).toContain('<p>hi</p>');
  });

  it('honors accent prop', () => {
    expect(renderSignatureBlock({ accent: 'green', children: '' })).toContain('sig-block--green');
    expect(renderSignatureBlock({ accent: 'amber', children: '' })).toContain('sig-block--amber');
    expect(renderSignatureBlock({ accent: 'red',   children: '' })).toContain('sig-block--red');
  });
});

describe('wireFieldHandlers', () => {
  it('reveal toggle flips data-revealed and swaps placeholder for plaintext', () => {
    document.body.innerHTML = renderConcealedRow({
      id: 'pw1',
      label: 'password',
      value: 'hunter2',
    });
    wireFieldHandlers(document.body);
    const row = document.querySelector('[data-field-id="pw1"]') as HTMLElement;
    const revealBtn = row.querySelector('[data-field-action="reveal"]') as HTMLButtonElement;
    const valueEl = row.querySelector('[data-field-role="value"]') as HTMLElement;
    expect(row.getAttribute('data-revealed')).toBe('false');
    expect(valueEl.textContent).toContain('••••');
    revealBtn.click();
    expect(row.getAttribute('data-revealed')).toBe('true');
    expect(valueEl.textContent).toBe('hunter2');
  });

  it('copy button writes the row value to the clipboard', async () => {
    const writeText = vi.fn().mockResolvedValue(undefined);
    Object.defineProperty(navigator, 'clipboard', {
      configurable: true,
      value: { writeText },
    });
    document.body.innerHTML = renderRow({
      label: 'email',
      value: 'alice@example.com',
      copyable: true,
    });
    wireFieldHandlers(document.body);
    const copyBtn = document.querySelector('[data-field-action="copy"]') as HTMLButtonElement;
    copyBtn.click();
    expect(writeText).toHaveBeenCalledWith('alice@example.com');
  });
});

describe('concealed-row round-trip with special characters', () => {
  it('reveals a value containing double quotes correctly', () => {
    document.body.innerHTML = renderConcealedRow({ id: 'pw', label: 'p', value: 'a"b"c' });
    wireFieldHandlers(document.body);
    const btn = document.querySelector('[data-field-action="reveal"]') as HTMLButtonElement;
    btn.click();
    const valueEl = document.querySelector('[data-field-role="value"]') as HTMLElement;
    expect(valueEl.textContent).toBe('a"b"c');
  });

  it('reveals a value containing single quotes correctly', () => {
    document.body.innerHTML = renderConcealedRow({ id: 'pw', label: 'p', value: "it's & ok" });
    wireFieldHandlers(document.body);
    const btn = document.querySelector('[data-field-action="reveal"]') as HTMLButtonElement;
    btn.click();
    const valueEl = document.querySelector('[data-field-role="value"]') as HTMLElement;
    expect(valueEl.textContent).toBe("it's & ok");
  });

  it('copies a value containing double quotes correctly', async () => {
    const writeText = vi.fn().mockResolvedValue(undefined);
    Object.defineProperty(navigator, 'clipboard', {
      configurable: true,
      value: { writeText },
    });
    document.body.innerHTML = renderRow({ label: 'p', value: 'a"b"c', copyable: true });
    wireFieldHandlers(document.body);
    (document.querySelector('[data-field-action="copy"]') as HTMLButtonElement).click();
    expect(writeText).toHaveBeenCalledWith('a"b"c');
  });
});
