import { EventTypes as CoreEventTypes, ContextEvent, IRequestLog, IHttpRequest, IHttpRequestDetail, IProjectExecutionLog, IRequestProxyInit, IProxyResult, IHttpProjectProxyInit, IHttpProjectStoreProxyInit } from '@api-client/core/build/browser.js';
import { PlatformBindings } from './PlatformBindings.js';

/**
 * The bindings for making HTTP request in the application.
 * The purpose is to run API requests using the `CoreEngine` class or
 * to run entire projects or folders.
 */
export abstract class ProxyBindings extends PlatformBindings {
  /**
   * This is used by the client side (main thread or the renderer process)
   * to define the current space the app is using. 
   * This space is used in some APIs instead of adding the space to the events system.
   */
  space = '';

  async initialize(): Promise<void> {
    window.addEventListener(CoreEventTypes.Transport.Core.request, this.handleCoreRequest.bind(this) as EventListener);
    window.addEventListener(CoreEventTypes.Transport.Core.httpProject, this.handleHttpProject.bind(this) as EventListener);
    window.addEventListener(CoreEventTypes.Transport.Http.send, this.handlerHttpSend.bind(this) as EventListener);
  }

  protected handleCoreRequest(e: ContextEvent<IRequestProxyInit, IProxyResult<IRequestLog>>): void {
    e.detail.result = this.coreRequest(e.detail);
  }

  protected handleHttpProject(e: ContextEvent<IHttpProjectProxyInit | IHttpProjectStoreProxyInit, IProxyResult<IProjectExecutionLog>>): void {
    const copy = { ...e.detail } as IHttpProjectStoreProxyInit;
    if (this.space && !copy.space) {
      copy.space = this.space;
    }
    e.detail.result = this.coreHttpProject(copy);
  }

  protected handlerHttpSend(e: ContextEvent<IHttpRequestDetail, Response>): void {
    const { request, init } = e.detail;
    e.detail.result = this.httpSend(request, init);
  }

  /**
   * Sends a single request without a context of a project.
   * 
   * @param init The request execution configuration
   * @returns The execution log with the variables evaluated during the run or `undefined` when the event was not handled.
   */
  abstract coreRequest(init: IRequestProxyInit): Promise<IProxyResult<IRequestLog>>;

  /**
   * For both a request or a folder (since it's all single configuration.)
   * 
   * @param init The project execution configuration
   * @returns The project execution log.
   */
  abstract coreHttpProject(init: IHttpProjectProxyInit | IHttpProjectStoreProxyInit): Promise<IProxyResult<IProjectExecutionLog>>;

  /**
   * Sends the request outside the Core engine, most probably using Fetch API.
   * Note, CORS may apply to the request.
   * 
   * @param request The base request definition.
   * @param init Optional request init options compatible with the Fetch API.
   * @returns Compatible with the Fetch API Response object.
   */
  abstract httpSend(request: IHttpRequest, init?: RequestInit): Promise<Response>;
}
