import { describe, it, expect } from 'vitest';
import { encodeBinary, decodeBinary } from '../message-binary';

function roundTrip<T>(v: T): T {
  // Simulate the JSON-ish channel: encode → JSON stringify/parse → decode.
  return decodeBinary(JSON.parse(JSON.stringify(encodeBinary(v))));
}

describe('message-binary transport', () => {
  it('round-trips a Uint8Array field through a JSON channel', () => {
    const bytes = new Uint8Array([0xff, 0xd8, 0x00, 0x10, 0xab]);
    const msg = { type: 'create_vault', carrierImageBytes: bytes.buffer, n: 3 };
    const out = roundTrip(msg) as typeof msg;
    expect(out.type).toBe('create_vault');
    expect(out.n).toBe(3);
    expect(new Uint8Array(out.carrierImageBytes)).toEqual(bytes);
  });

  it('preserves a raw ArrayBuffer', () => {
    const buf = new Uint8Array([1, 2, 3, 4]).buffer;
    const out = roundTrip({ bytes: buf }) as { bytes: ArrayBuffer };
    expect(new Uint8Array(out.bytes)).toEqual(new Uint8Array([1, 2, 3, 4]));
  });

  it('round-trips binary nested in response.data', () => {
    const ref = new Uint8Array([9, 8, 7]);
    const resp = { ok: true, data: { referenceImageBytes: ref, deviceName: 'X' } };
    const out = roundTrip(resp) as typeof resp;
    expect(out.data.deviceName).toBe('X');
    expect(new Uint8Array(out.data.referenceImageBytes as unknown as ArrayBuffer)).toEqual(ref);
  });

  it('leaves plain number[] arrays (e.g. TOTP secrets) untouched', () => {
    const msg = { core: { type: 'totp', secret: [0x48, 0x65, 0x6c] } };
    const out = roundTrip(msg) as typeof msg;
    expect(out.core.secret).toEqual([0x48, 0x65, 0x6c]);
    expect(Array.isArray(out.core.secret)).toBe(true);
  });

  it('handles an empty Uint8Array without corruption', () => {
    const out = roundTrip({ bytes: new Uint8Array(0).buffer }) as { bytes: ArrayBuffer };
    expect(new Uint8Array(out.bytes).length).toBe(0);
  });

  it('round-trips a larger buffer (chunked base64, no stack overflow)', () => {
    const big = new Uint8Array(100_000);
    for (let i = 0; i < big.length; i++) big[i] = i % 256;
    const out = roundTrip({ bytes: big.buffer }) as { bytes: ArrayBuffer };
    expect(new Uint8Array(out.bytes)).toEqual(big);
  });

  it('is a structural no-op when there is no binary', () => {
    const msg = { type: 'is_unlocked', nested: { a: 1, b: ['x', 'y'], c: null } };
    expect(roundTrip(msg)).toEqual(msg);
  });
});
