import { describe, expect, it } from 'vitest';
import { csvCell, toCsv } from './csv';

describe('csvCell', () => {
  it('leaves plain text alone', () => {
    expect(csvCell('The Harbor Tap')).toBe('The Harbor Tap');
    expect(csvCell('')).toBe('');
    expect(csvCell(null)).toBe('');
    expect(csvCell(undefined)).toBe('');
  });

  it('quotes commas, quotes and line breaks (RFC 4180)', () => {
    expect(csvCell('Bar, Grill')).toBe('"Bar, Grill"');
    expect(csvCell('The "Best" Pub')).toBe('"The ""Best"" Pub"');
    expect(csvCell('line one\nline two')).toBe('"line one\nline two"');
    expect(csvCell('a\r\nb')).toBe('"a\r\nb"');
  });

  it('neutralises spreadsheet formulas', () => {
    expect(csvCell('=HYPERLINK("http://evil.example","x")')).toBe(`"'=HYPERLINK(""http://evil.example"",""x"")"`);
    expect(csvCell('+1 555 0100')).toBe("'+1 555 0100");
    expect(csvCell('-2+3')).toBe("'-2+3");
    expect(csvCell('@SUM(A1:A9)')).toBe("'@SUM(A1:A9)");
    expect(csvCell('\t=1+1')).toBe("'\t=1+1");
    expect(csvCell('\r=1+1')).toBe(`"'\r=1+1"`);
    // Only a leading character is dangerous.
    expect(csvCell('a=b')).toBe('a=b');
  });

  it('formats numbers, booleans, dates and arrays', () => {
    expect(csvCell(-5)).toBe('-5');
    expect(csvCell(3)).toBe('3');
    expect(csvCell(Number.NaN)).toBe('');
    expect(csvCell(true)).toBe('true');
    expect(csvCell(new Date(Date.UTC(2026, 9, 29, 21, 0)))).toBe('2026-10-29T21:00:00.000Z');
    expect(csvCell(['FRI', 'SAT'])).toBe('FRI; SAT');
    expect(csvCell(['=cmd', 'x'])).toBe("'=cmd; x");
  });
});

describe('toCsv', () => {
  it('builds a BOM-prefixed CRLF document', () => {
    const csv = toCsv(['name', 'tvs'], [
      ['Ocean, Ave', 4],
      ['=evil()', null],
    ]);
    expect(csv).toBe('﻿name,tvs\r\n"Ocean, Ave",4\r\n\'=evil(),\r\n');
  });
});
