const { test, describe } = require('node:test');
const assert = require('node:assert');
const {
  createRegister,
  createStatus,
  createCommand,
  TYPE_REGISTER,
  TYPE_STATUS,
  TYPE_COMMAND,
  MIN_PROTOCOL_VERSION,
  PROTOCOL_VERSION,
  isSupportedClientProtocolVersion,
  CAPABILITY_CAMERA_ZOOM,
  CAPABILITY_HUD_LAYOUT,
  deviceSupportsCommand,
  CMD_SET_CAMERA_ZOOM,
  CMD_SET_HUD_LAYOUT,
  STATE_STOPPING,
} = require('./protocol');

describe('protocol', () => {
  test('MIN_PROTOCOL_VERSION <= PROTOCOL_VERSION', () => {
    assert.ok(MIN_PROTOCOL_VERSION <= PROTOCOL_VERSION);
  });

  test('deviceSupportsCommand: legacy/missing caps = allow', () => {
    assert.strictEqual(deviceSupportsCommand(undefined, CMD_SET_CAMERA_ZOOM), true);
    assert.strictEqual(deviceSupportsCommand({ platform: 'ios' }, CMD_SET_CAMERA_ZOOM), true);
  });

  test('deviceSupportsCommand: explicit false skips optional commands', () => {
    assert.strictEqual(deviceSupportsCommand({ [CAPABILITY_CAMERA_ZOOM]: false }, CMD_SET_CAMERA_ZOOM), false);
    assert.strictEqual(deviceSupportsCommand({ [CAPABILITY_HUD_LAYOUT]: false }, CMD_SET_HUD_LAYOUT), false);
    assert.strictEqual(deviceSupportsCommand({ [CAPABILITY_CAMERA_ZOOM]: true }, CMD_SET_CAMERA_ZOOM), true);
  });

  test('isSupportedClientProtocolVersion accepts inclusive range', () => {
    assert.strictEqual(isSupportedClientProtocolVersion(MIN_PROTOCOL_VERSION), true);
    assert.strictEqual(isSupportedClientProtocolVersion(PROTOCOL_VERSION), true);
    assert.strictEqual(isSupportedClientProtocolVersion(MIN_PROTOCOL_VERSION - 1), false);
    assert.strictEqual(isSupportedClientProtocolVersion(PROTOCOL_VERSION + 1), false);
    assert.strictEqual(isSupportedClientProtocolVersion(1.5), false);
    assert.strictEqual(isSupportedClientProtocolVersion('1'), false);
    assert.strictEqual(isSupportedClientProtocolVersion(NaN), false);
  });

  test('createRegister returns valid register message', () => {
    const msg = createRegister('id1', 'Phone');
    assert.strictEqual(msg.type, TYPE_REGISTER);
    assert.strictEqual(msg.protocolVersion, PROTOCOL_VERSION);
    assert.strictEqual(msg.deviceId, 'id1');
    assert.strictEqual(msg.deviceName, 'Phone');
  });

  test('createRegister with capabilities and pin', () => {
    const msg = createRegister('id2', 'Tablet', { video: true }, '1234');
    assert.strictEqual(msg.type, TYPE_REGISTER);
    assert.strictEqual(msg.deviceId, 'id2');
    assert.strictEqual(msg.deviceName, 'Tablet');
    assert.deepStrictEqual(msg.capabilities, { video: true });
    assert.strictEqual(msg.pin, '1234');
  });

  test('createStatus returns valid status message', () => {
    const msg = createStatus('id1', 'idle');
    assert.strictEqual(msg.type, TYPE_STATUS);
    assert.strictEqual(msg.deviceId, 'id1');
    assert.strictEqual(msg.state, 'idle');
  });

  test('createStatus with opts', () => {
    const msg = createStatus('id1', 'recording', { durationSec: 10, battery: 80 });
    assert.strictEqual(msg.type, TYPE_STATUS);
    assert.strictEqual(msg.deviceId, 'id1');
    assert.strictEqual(msg.state, 'recording');
    assert.strictEqual(msg.durationSec, 10);
    assert.strictEqual(msg.battery, 80);
  });

  test('createStatus stopping state', () => {
    const msg = createStatus('id1', STATE_STOPPING, { durationSec: 42.5, sessionId: 's1' });
    assert.strictEqual(msg.state, 'stopping');
    assert.strictEqual(msg.durationSec, 42.5);
    assert.strictEqual(msg.sessionId, 's1');
  });

  test('createCommand returns valid command message', () => {
    const msg = createCommand('START_RECORDING');
    assert.strictEqual(msg.type, TYPE_COMMAND);
    assert.strictEqual(msg.cmd, 'START_RECORDING');
    assert.strictEqual(msg.markerPayload, undefined);
  });

  test('createCommand with markerPayload', () => {
    const payload = { sessionId: 's1', startTimeIso: '2025-01-01T00:00:00Z' };
    const msg = createCommand('START_RECORDING', payload);
    assert.strictEqual(msg.type, TYPE_COMMAND);
    assert.strictEqual(msg.cmd, 'START_RECORDING');
    assert.deepStrictEqual(msg.markerPayload, payload);
  });
});
