// Calls to the plugin's own REST routes (/wp-json/stand-chat/v1/…). WordPress
// adds the REST nonce through @wordpress/api-fetch.
import apiFetch from '@wordpress/api-fetch';
import { __ } from '@wordpress/i18n';

export class RequestError extends Error {
  readonly code: string;
  readonly status: number;
  readonly details: Record<string, unknown>;

  constructor(code: string, message: string, status: number, details: Record<string, unknown> = {}) {
    super(message);
    this.code = code;
    this.status = status;
    this.details = details;
  }

  get reconnect(): boolean {
    return this.code === 'stand_reconnect_needed';
  }

  get ownerOnly(): boolean {
    return this.code === 'stand_owner_only';
  }

  get unreachable(): boolean {
    return this.code === 'stand_unreachable';
  }

  /** Stand-in coverage is off, and turning it on needs the person's OK. */
  get coverageConsent(): boolean {
    return this.code === 'stand_coverage_consent';
  }
}

interface WpErrorBody {
  code?: string;
  message?: string;
  data?: { status?: number; [key: string]: unknown };
}

let basePath = '/stand-chat/v1';
// The connection the page was loaded on. WordPress turns away a change from a
// page loaded before it was connected again, such as to another Site.
let connection = '';

export function setBasePath(path: string): void {
  basePath = path;
}

export function setConnection(fingerprint: string): void {
  connection = fingerprint;
}

export async function request<T>(method: 'GET' | 'POST' | 'PUT' | 'DELETE', path: string, data?: unknown): Promise<T> {
  try {
    const headers = connection ? { 'X-Stand-Chat-Connection': connection } : undefined;
    return await apiFetch<T>({ path: `${basePath}${path}`, method, data, headers });
  } catch (error) {
    const body = (error ?? {}) as WpErrorBody;
    throw new RequestError(
      body.code ?? 'unknown_error',
      body.message ?? __('Something went wrong. Try again.', 'stand-chat'),
      Number(body.data?.status ?? 0),
      (body.data ?? {}) as Record<string, unknown>,
    );
  }
}

export const get = <T>(path: string): Promise<T> => request<T>('GET', path);
export const post = <T>(path: string, data?: unknown): Promise<T> => request<T>('POST', path, data ?? {});
export const put = <T>(path: string, data?: unknown): Promise<T> => request<T>('PUT', path, data ?? {});
export const del = <T>(path: string): Promise<T> => request<T>('DELETE', path);

export function errorMessage(error: unknown): string {
  if (error instanceof RequestError) return error.message;
  if (error instanceof Error) return error.message;
  return __('Something went wrong. Try again.', 'stand-chat');
}
