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

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

function view(overrides: Partial<WorkerContinuityViewFrame> = {}): WorkerContinuityViewFrame {
  return {
    workerId, runId, runTitle: 'Execution Continuity', workerName: '/root/worker-a',
    displayName: '/root/worker-a', assignmentTitle: 'Backend migration',
    disposition: 'awaiting_execution', policyMode: 'auto', runPolicyMode: 'auto', policySource: 'run', workerPolicyOverride: false,
    deadmanFallbackEnabled: false, deadmanThresholdMs: 1_800_000, attemptNumber: 2, autoResumeCount: 1,
    lastProgressAt: null, needsUser: false, isWorking: false, isResuming: true, blockReason: null, pauseReason: null,
    noProgressAttempts: 0, stallWarningAt: null, stallPausedAt: null, conversationUrl: 'https://chatgpt.com/c/c-1', recentEvents: [],
    ...overrides,
  };
}

test('operator action frames map worker and run 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',
  });
  assert.deepEqual(operatorActionFrame('browser-1', 'op-5', { kind: 'chatgpt-orchestrator.ui', action: 'set-run-auto-resume', runId, enabled: true }), {
    protocolVersion: PROTOCOL_VERSION, type: 'operator.action', executorId: 'browser-1', requestId: 'op-5', runId, action: 'set_run_auto_resume', enabled: true, idempotencyKey: 'op-5',
  });
  assert.equal(operatorActionFrame('browser-1', 'op-6', { kind: 'chatgpt-orchestrator.ui', action: 'pause-run', runId }).action, 'pause_run');
  assert.equal(operatorActionFrame('browser-1', 'op-7', { kind: 'chatgpt-orchestrator.ui', action: 'resume-run', runId }).action, 'resume_run');
  assert.equal(operatorActionFrame('browser-1', 'op-8', { kind: 'chatgpt-orchestrator.ui', action: 'stop-run', runId }).action, 'cancel_run');
});

test('control server parser accepts authoritative continuity views and operator results', () => {
  const continuityView = view();
  const continuity = parseContinuityControlServerFrame({ protocolVersion: PROTOCOL_VERSION, type: 'worker.continuity', executorId: 'browser-1', view: continuityView });
  assert.equal(continuity?.kind, 'worker-continuity');
  assert.equal(continuity?.frame.view.isResuming, true);
  assert.equal(continuity?.frame.view.runPolicyMode, 'auto');
  const result = parseContinuityControlServerFrame({ protocolVersion: PROTOCOL_VERSION, type: 'operator.result', executorId: 'browser-1', requestId: 'op-1', workerId, success: true, view: continuityView });
  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 preserves authoritative stall, run and recent-event metadata', () => {
  const continuityView = view({
    disposition: 'paused', policySource: 'worker', workerPolicyOverride: true, 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', detail: null }], isResuming: false,
  });
  const parsed = parseContinuityControlServerFrame({ protocolVersion: PROTOCOL_VERSION, type: 'worker.continuity', executorId: 'browser-1', view: continuityView });
  assert.equal(parsed?.kind, 'worker-continuity');
  assert.equal(parsed?.frame.view.policySource, 'worker');
  assert.equal(parsed?.frame.view.workerPolicyOverride, true);
  assert.equal(parsed?.frame.view.pauseReason, 'stall');
  assert.equal(parsed?.frame.view.recentEvents[0]?.type, 'continuation.paused_for_stall');
});
