// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import {InspectorFrontendHostInstance} from './InspectorFrontendHost.js';
import type {DispatchHttpRequestRequest, DispatchHttpRequestResult} from './InspectorFrontendHostAPI.js';

export enum ErrorType {
  HTTP_RESPONSE_UNAVAILABLE = 'HTTP_RESPONSE_UNAVAILABLE',
  NOT_FOUND = 'NOT_FOUND',
  ABORT = 'ABORT',
}

export class DispatchHttpRequestError extends Error {
  constructor(readonly type: ErrorType, readonly response?: DispatchHttpRequestResult, options?: ErrorOptions) {
    super(undefined, options);
  }
}

export async function makeHttpRequest<R>(
    request: DispatchHttpRequestRequest, options?: {signal?: AbortSignal}): Promise<R> {
  const signal = options?.signal;
  if (signal?.aborted) {
    throw new DispatchHttpRequestError(ErrorType.ABORT);
  }

  const response = await new Promise<DispatchHttpRequestResult>((resolve, reject) => {
    const onAbort = (): void => {
      reject(new DispatchHttpRequestError(ErrorType.ABORT));
    };

    signal?.addEventListener('abort', onAbort, {once: true});
    InspectorFrontendHostInstance.dispatchHttpRequest(request, result => {
      signal?.removeEventListener('abort', onAbort);
      resolve(result);
    });
  });

  debugLog({request, response});
  if (response.statusCode === 404) {
    throw new DispatchHttpRequestError(ErrorType.NOT_FOUND, response);
  }

  if ('response' in response && response.statusCode === 200) {
    if (request.streamId && !response.response) {
      return null as R;
    }
    try {
      return JSON.parse(response.response) as R;
    } catch (err) {
      throw new DispatchHttpRequestError(ErrorType.HTTP_RESPONSE_UNAVAILABLE, response, {cause: err});
    }
  }

  throw new DispatchHttpRequestError(ErrorType.HTTP_RESPONSE_UNAVAILABLE, response);
}

function isDebugMode(): boolean {
  return Boolean(localStorage.getItem('debugDispatchHttpRequestEnabled'));
}

function debugLog(...log: unknown[]): void {
  if (!isDebugMode()) {
    return;
  }

  // eslint-disable-next-line no-console
  console.log('debugLog', ...log);
}

function setDebugDispatchHttpRequestEnabled(enabled: boolean): void {
  if (enabled) {
    localStorage.setItem('debugDispatchHttpRequestEnabled', 'true');
  } else {
    localStorage.removeItem('debugDispatchHttpRequestEnabled');
  }
}

// @ts-expect-error
globalThis.setDebugDispatchHttpRequestEnabled = setDebugDispatchHttpRequestEnabled;
