import { chooseMove } from './ai';
import {
  AIWorkerChooseMoveRequest,
  AIWorkerErrorMessage,
  AIWorkerRequestMessage,
  AIWorkerResponseMessage,
} from './ai-worker-protocol';
import { CardInferenceEngine } from './card-inference';
import { CardTracker } from './card-tracker';

interface AIWorkerScope {
  addEventListener(type: 'message', listener: (event: MessageEvent<AIWorkerRequestMessage>) => void): void;
  postMessage(message: AIWorkerResponseMessage): void;
}

const workerScope = globalThis as unknown as AIWorkerScope;

function serializeError(requestId: string, error: unknown): AIWorkerErrorMessage {
  if (error instanceof Error) {
    return {
      type: 'error',
      requestId,
      error: {
        message: error.message,
        name: error.name,
        stack: error.stack,
      },
    };
  }

  return {
    type: 'error',
    requestId,
    error: {
      message: typeof error === 'string' ? error : 'Unknown AI worker error',
      name: 'Error',
    },
  };
}

async function handleChooseMove(request: AIWorkerChooseMoveRequest): Promise<void> {
  const tracker = request.trackerSnapshot
    ? CardTracker.fromSnapshot(request.trackerSnapshot)
    : undefined;

  const inference = request.inferenceSnapshot && tracker
    ? CardInferenceEngine.fromSnapshot(request.inferenceSnapshot, tracker)
    : undefined;

  try {
    const move = await chooseMove(
      request.state,
      request.playerIdx,
      request.difficulty,
      tracker,
      (progress) => {
        workerScope.postMessage({
          type: 'progress',
          requestId: request.requestId,
          progress,
        });
      },
      inference ? { inference } : undefined,
    );

    workerScope.postMessage({
      type: 'result',
      requestId: request.requestId,
      move,
    });
  } catch (error) {
    workerScope.postMessage(serializeError(request.requestId, error));
  }
}

workerScope.addEventListener('message', (event: MessageEvent<AIWorkerRequestMessage>) => {
  const message = event.data;
  if (message.type !== 'choose-move') {
    return;
  }

  void handleChooseMove(message);
});

export {};