/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @noformat
 * @oncall flow
 */

// https://github.com/WebAssembly/design/blob/master/JS.md
// https://developer.mozilla.org/en-US/docs/WebAssembly
// https://github.com/WebAssembly/design/blob/master/Web.md

type BufferSource = $TypedArray | ArrayBuffer;
type ImportExportKind = 'function' | 'table' | 'memory' | 'global';
type ImportObject = Object;
type ResultObject = {
  module: WebAssembly$Module,
  instance: WebAssembly$Instance,
  ...
};

// https://github.com/WebAssembly/design/blob/master/JS.md#exported-function-exotic-objects
declare class ExportedFunctionExoticObject extends Function {
  (): mixed;
}

declare class WebAssembly$Module {
  constructor(bufferSource: BufferSource): void;

  static exports(moduleObject: WebAssembly$Module): Array<{
    name: string,
    kind: ImportExportKind,
    ...
  }>;
  static imports(moduleObject: WebAssembly$Module): Array<{
    name: string,
    name: string,
    kind: ImportExportKind,
    ...
  }>;
  static customSections(moduleObject: WebAssembly$Module, sectionName: string): Array<ArrayBuffer>;
}

declare class WebAssembly$Instance {
  constructor(moduleObject: WebAssembly$Module, importObject?: ImportObject): void;

  +exports: { [exportedFunction: string]: ExportedFunctionExoticObject, ... };
}

type MemoryDescriptor = {
  initial: number,
  maximum?: number,
  ...
};

declare class WebAssembly$Memory {
  constructor(memoryDescriptor: MemoryDescriptor): void;

  +buffer: ArrayBuffer;

  grow(delta: number): number;
}

type TableDescriptor = {
  element: 'anyfunc',
  initial: number,
  maximum?: number,
  ...
};

declare class WebAssembly$Table {
  constructor(tableDescriptor: TableDescriptor): void;

  +length: number;

  grow(delta: number): number;
  get(index: number): ExportedFunctionExoticObject;
  set(index: number, value: ExportedFunctionExoticObject): void;
}

declare class WebAssembly$CompileError extends Error {}
declare class WebAssembly$LinkError extends Error {}
declare class WebAssembly$RuntimeError extends Error {}

declare function WebAssembly$instantiate(bufferSource: BufferSource, importObject?: ImportObject): Promise<ResultObject>;
declare function WebAssembly$instantiate(moduleObject: WebAssembly$Module, importObject?: ImportObject): Promise<WebAssembly$Instance>;

declare var WebAssembly: {
  Module: typeof WebAssembly$Module,
  Instance: typeof WebAssembly$Instance,
  Memory: typeof WebAssembly$Memory,
  Table: typeof WebAssembly$Table,
  CompileError: typeof WebAssembly$CompileError,
  LinkError: typeof WebAssembly$LinkError,
  RuntimeError: typeof WebAssembly$RuntimeError,
  validate(bufferSource: BufferSource): boolean,
  compile(bufferSource: BufferSource): Promise<WebAssembly$Module>,
  instantiate: typeof WebAssembly$instantiate,
  // web embedding API
  compileStreaming(source: Response | Promise<Response>): Promise<WebAssembly$Module>,
  instantiateStreaming(source: Response | Promise<Response>, importObject?: ImportObject): Promise<ResultObject>,
  ...
}
