import assert from 'node:assert/strict';
import test from 'node:test';
import { operatorActionFrame, parseContinuityControlServerFrame } from '../src/control-bridge.js';
import { PROTOCOL_VERSION } from '@platform-modules/chatgpt-orchestrator-protocol';

const workerId = 'wrk_00000000-0000-0000-0000-000000000001';

test('operator action frames map UI actions onto authenticated executor transport', () => {
  assert.deepEqual(operatorActionFrame('browser-1', 'op-1', { kind: 'chatgpt-orchestrator.ui', action: 'pause', workerId }), {
    protocolVersion: PROTOCOL_VERSION, type: 'operator.action', executorId: 'browser-1', requestId: 'op-1', workerId, action: 'pause', idempotencyKey: 'op-1',
  });
  assert.equal(operatorActionFrame('browser-1', 'op-2', { kind: 'chatgpt-orchestrator.ui', action: 'continue-now', workerId }).action, 'continue_now');
  assert.deepEqual(operatorActionFrame('browser-1', 'op-2b', { kind: 'chatgpt-orchestrator.ui', action: 'continue-anyway', workerId }), {
    protocolVersion: PROTOCOL_VERSION, type: 'operator.action', executorId: 'browser-1', requestId: 'op-2b', workerId, action: 'continue_now', overrideBlock: true, idempotencyKey: 'op-2b',
  });
  assert.equal(operatorActionFrame('browser-1', 'op-3', { kind: 'chatgpt-orchestrator.ui', action: 'stop', workerId }).action, 'cancel');
  assert.deepEqual(operatorActionFrame('browser-1', 'op-4', { kind: 'chatgpt-orchestrator.ui', action: 'set-auto-resume', workerId, enabled: false }), {
    protocolVersion: PROTOCOL_VERSION, type: 'operator.action', executorId: 'browser-1', requestId: 'op-4', workerId, action: 'set_auto_resume', enabled: false, idempotencyKey: 'op-4',
  });
});

test('control server parser accepts authoritative continuity views and operator results', () => {
  const view = { workerId, disposition: 'awaiting_execution', policyMode: 'auto', attemptNumber: 2, autoResumeCount: 1, lastProgressAt: null, needsUser: false, isWorking: false, isResuming: true };
  const continuity = parseContinuityControlServerFrame({ protocolVersion: PROTOCOL_VERSION, type: 'worker.continuity', executorId: 'browser-1', view });
  assert.equal(continuity?.kind, 'worker-continuity');
  assert.equal(continuity?.frame.view.isResuming, true);
  assert.equal(continuity?.frame.view.stallMetadataAvailable, false);
  const result = parseContinuityControlServerFrame({ protocolVersion: PROTOCOL_VERSION, type: 'operator.result', executorId: 'browser-1', requestId: 'op-1', workerId, success: true, view });
  assert.equal(result?.kind, 'operator-result');
  assert.equal(result?.frame.success, true);
});

test('control server parser fails closed on malformed or mismatched protocol frames', () => {
  assert.throws(() => parseContinuityControlServerFrame({ protocolVersion: 999, type: 'operator.result', executorId: 'browser-1', requestId: 'op-1', workerId, success: true }), /Invalid operator.result/);
  assert.throws(() => parseContinuityControlServerFrame({ protocolVersion: PROTOCOL_VERSION, type: 'worker.continuity', executorId: 'browser-1', view: { workerId, disposition: 'running' } }), /Invalid worker.continuity/);
  assert.equal(parseContinuityControlServerFrame({ protocolVersion: PROTOCOL_VERSION, type: 'executor.ready' }), null);
});


test('control parser accepts additive operator metadata without requiring backend schema changes', () => {
  const view = { workerId, disposition: 'paused', policyMode: 'auto', policySource: 'worker', attemptNumber: 8, autoResumeCount: 7, lastProgressAt: '2026-08-21T03:00:00.000Z', blockReason: 'Waiting for approval', pauseReason: 'stall', noProgressAttempts: 20, stallWarningAt: '2026-08-21T03:10:00.000Z', stallPausedAt: '2026-08-21T03:20:00.000Z', recentEvents: [{ type: 'continuation.paused_for_stall', timestamp: '2026-08-21T03:20:00.000Z' }], needsUser: false, isWorking: false, isResuming: false };
  const parsed = parseContinuityControlServerFrame({ protocolVersion: PROTOCOL_VERSION, type: 'worker.continuity', executorId: 'browser-1', view });
  assert.equal(parsed?.kind, 'worker-continuity');
  assert.equal(parsed?.frame.view.policySource, 'worker');
  assert.equal(parsed?.frame.view.pauseReason, 'stall');
  assert.equal(parsed?.frame.view.stallMetadataAvailable, true);
  assert.equal(parsed?.frame.view.recentEvents?.[0]?.type, 'continuation.paused_for_stall');
});
