declare module "@univerjs/core/facade" {
  import type { ISocket } from "@univerjs/network";

  import type { FNetwork } from "@univerjs/network/facade";

  type Event = unknown;

  type HeadersInit = unknown;

  type MessageEvent = unknown;

  type WebSocket = { send(data: unknown): void };

  interface IFUniverNetworkMixin {
      /**
       * Get the network API of Univer, with the help of which you can send HTTP requests.
       */
      getNetwork(): FNetwork;
      /**
       * Set WebSocket URL for WebSocketService
       *
       * @param {string} url WebSocket URL
       * @returns {ISocket} WebSocket instance
       * @example
       * ```typescript
       * // Replace the URL with the address of your own WebSocket service
       * const ws = univerAPI.createSocket('wss://47.100.177.253:8449/ws');
       *
       * ws.open$.subscribe(() => {
       *   console.log('websocket opened');
       *   ws.send('hello');
       * });
       *
       * ws.message$.subscribe((message) => {
       *   console.log('websocket message', message);
       *   const content = JSON.parse(message.data).content;
       *   if (!content.includes('command')) {
       *     return;
       *   }
       *
       *   const commandInfo = JSON.parse(content);
       *   const { command, options } = commandInfo;
       *   const { id, params } = command;
       *
       *   // Upon receiving collaborative data, it is locally saved
       *   univerAPI.executeCommand(id, params, options);
       * });
       *
       * ws.close$.subscribe(() => {
       *   console.log('websocket closed');
       * });
       *
       * ws.error$.subscribe((error) => {
       *   console.log('websocket error', error);
       * });
       *
       * univerAPI.onCommandExecuted((command, options) => {
       *   // Only synchronize local mutations
       *   if (command.type !== 2 || options?.fromCollab || options?.onlyLocal || command.id === 'doc.mutation.rich-text-editing') {
       *     return;
       *   }
       *
       *   const commandInfo = JSON.stringify({ command, options: { fromCollab: true } });
       *   ws.send(commandInfo);
       * });
       * ```
       */
      createSocket(url: string): ISocket;
  }
}

declare module "@univerjs/network" {
  // @ts-ignore: optional external type dependency may be absent in generated workspaces.
  import type { Observable } from "rxjs";

  type Event = unknown;

  type HeadersInit = unknown;

  type MessageEvent = unknown;

  type WebSocket = { send(data: unknown): void };

  /**
   * It wraps headers of HTTP requests' and responses' headers.
   */
  class HTTPHeaders {
      forEach(callback: (name: string, value: string[]) => void): void;
      has(key: string): boolean;
      get(key: string): string[] | null;
      set(key: string, value: string | number | boolean): void;
      toHeadersInit(body?: any): HeadersInit;
  }

  type HTTPResponseType = 'arraybuffer' | 'blob' | 'json' | 'text';

  interface IRequestParams {
      /** Query params. These params would be append to the url before the request is sent. */
      params?: {
          [param: string]: string | number | boolean;
      };
      /** Query headers. */
      headers?: {
          [key: string]: string | number | boolean;
      };
      /** Expected types of the response data. */
      responseType?: HTTPResponseType;
      withCredentials?: boolean;
      /**
       * Should report progress.
       */
      reportProgress?: boolean;
  }

  interface IPostRequestParams extends IRequestParams {
      body?: unknown;
  }

  type HTTPRequestMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';

  type HTTPEvent<T> = HTTPResponse<T> | HTTPProgress;

  enum HTTPEventType {
      DownloadProgress = 0,
      Response = 1
  }

  /**
   * Wraps success response info.
   */
  class HTTPResponse<T> {
      readonly type = HTTPEventType.Response;
      readonly body: T;
      readonly headers: HTTPHeaders;
      readonly status: number;
      readonly statusText: string;
  }

  /**
   * Progress event for HTTP request. Usually used for reporting download/upload progress or SSE streaming.
   */
  class HTTPProgress {
      /**
       * Total number of bytes to download. Depending on the request or
       * response, this may not be computable and thus may not be present.
       */
      readonly total: number | undefined;
      /**
       * Number of bytes downloaded.
       */
      readonly loaded: number;
      /**
       * The partial response body as downloaded so far.
       *
       * Only present if the responseType was `text`.
       */
      readonly partialText?: string | undefined;
      readonly type = HTTPEventType.DownloadProgress;
  }

  type SocketBodyType = Parameters<WebSocket['send']>[0];

  /**
   * An interface that represents a socket connection.
   */
  interface ISocket {
      URL: string;
      close(code?: number, reason?: string): void;
      /**
       * Send a message to the remote server.
       */
      send(data: SocketBodyType): void;
      close$: Observable<Event>;
      error$: Observable<Event>;
      message$: Observable<MessageEvent>;
      open$: Observable<Event>;
  }
}

declare module "@univerjs/network/facade" {
  import type { HTTPEvent, HTTPRequestMethod, HTTPResponse, IPostRequestParams, IRequestParams } from "@univerjs/network";

  // @ts-ignore: optional external type dependency may be absent in generated workspaces.
  import type { Observable } from "rxjs";

  type Event = unknown;

  type HeadersInit = unknown;

  type MessageEvent = unknown;

  type WebSocket = { send(data: unknown): void };

  /**
   * This Facade provides a set of methods to make HTTP requests. You should not
   * create an instance of this class directly, instead, use `getNetwork` of
   * {@link FUniver} instead.
   *
   * @hideconstructor
   */
  class FNetwork {
      /**
       * Send a GET request to the server.
       * @param {string} url - The requested URL.
       * @param {IRequestParams} [params] - Query parameters.
       * @returns {Promise<HTTPResponse>} Network response.
       */
      get<T>(url: string, params?: IRequestParams): Promise<HTTPResponse<T>>;
      /**
       * Send a POST request to the server.
       * @param {string} url - The requested URL.
       * @param {IPostRequestParams} [params] - Query parameters.
       * @returns {Promise<HTTPResponse>} Network response.
       */
      post<T>(url: string, params?: IPostRequestParams): Promise<HTTPResponse<T>>;
      /**
       * Send a PUT request to the server.
       * @param {string} url - The requested URL
       * @param {IPostRequestParams} [params] - Query parameters
       * @returns {Promise<HTTPResponse>} Network response
       */
      put<T>(url: string, params?: IPostRequestParams): Promise<HTTPResponse<T>>;
      /**
       * Send DELETE request to the server.
       * @param {string} url - The requested URL
       * @param {IRequestParams} [params] - Query parameters
       * @returns {Promise<HTTPResponse>} Network response
       */
      delete<T>(url: string, params?: IRequestParams): Promise<HTTPResponse<T>>;
      /**
       * Send PATCH request to the server.
       * @param {string} url - The requested URL
       * @param {IPostRequestParams} [params] - Query parameters
       * @returns {Promise<HTTPResponse>} Network response
       */
      patch<T>(url: string, params?: IPostRequestParams): Promise<HTTPResponse<T>>;
      /**
       * Request for a stream of server-sent events. Instead of a single response, the server sends a stream of responses,
       * Univer wraps the stream in an [`Observable`](https://rxjs.dev/guide/observable) which you can call `subscribe` on.
       * @param {HTTPRequestMethod} method - HTTP request method
       * @param {string} url - The requested URL
       * @param {IPostRequestParams} [params] - params Query parameters
       * @returns {Observable<HTTPEvent>} An observable that emits the network response.
       */
      getSSE<T>(method: HTTPRequestMethod, url: string, params?: IPostRequestParams): Observable<HTTPEvent<T>>;
  }
}

declare module "@univerjs/core/facade" {
  import type { ISocket } from "@univerjs/network";

  import type { FNetwork } from "@univerjs/network/facade";

  interface FUniver extends IFUniverNetworkMixin {
  }
}
