import type { KdlApiMethod, KdlError, KdlWasmApi, MotionDiagnostic } from "./types.js";

export interface KdlRpcRequest<T = unknown> {
  id: number;
  method: KdlApiMethod;
  payload: T;
}

export interface KdlRpcErrorPayload {
  code: string;
  message: string;
  diagnostics?: MotionDiagnostic[];
}

export interface KdlRpcResponse<T = unknown> {
  id: number;
  ok: boolean;
  result?: T;
  error?: KdlRpcErrorPayload;
}

export class KdlStructuredError extends Error implements KdlError {
  readonly code: string;
  readonly diagnostics: MotionDiagnostic[];

  constructor(code: string, message: string, diagnostics?: MotionDiagnostic[]) {
    super(message);
    this.name = "KdlStructuredError";
    this.code = code;
    this.diagnostics = diagnostics ?? [
      {
        severity: "error",
        code,
        message
      }
    ];
  }
}

export type KdlRuntimeHandlers = Partial<{
  [Method in keyof KdlWasmApi]: (...args: unknown[]) => Promise<unknown> | unknown;
}>;

export function createRpcError(
  code: string,
  message: string,
  diagnostics?: MotionDiagnostic[]
): KdlRpcErrorPayload {
  return {
    code,
    message,
    diagnostics:
      diagnostics ??
      [
        {
          severity: "error",
          code,
          message
        }
      ]
  };
}

export function normalizeThrownError(error: unknown): KdlRpcErrorPayload {
  if (error instanceof KdlStructuredError) {
    return createRpcError(error.code, error.message, error.diagnostics);
  }

  if (error instanceof Error) {
    return createRpcError("KDL_WORKER_ERROR", error.message);
  }

  return createRpcError("KDL_WORKER_ERROR", String(error));
}

export function rpcErrorToException(error: KdlRpcErrorPayload): KdlStructuredError {
  return new KdlStructuredError(error.code, error.message, error.diagnostics);
}
