import { AuthApi } from "./AuthApi";

interface APIResponse {
  data: any;
  status: number;
}

export class ApiError extends Error {
  constructor(message: string, public code: number, public data: any) {
    super(message);
  }
}

export class APIClient {
  /**
   * Get backend URL
   */
  static backendURL(): string {
    const URL = import.meta.env.VITE_APP_BACKEND ?? "";
    if (URL.length === 0) throw new Error("Backend URL undefined!");
    return URL;
  }

  /**
   * Check out whether the backend is accessed through
   * HTTPS or not
   */
  static IsBackendSecure(): boolean {
    return this.backendURL().startsWith("https");
  }

  /**
   * Perform a request on the backend
   */
  static async exec(args: {
    uri: string;
    method: "GET" | "POST" | "DELETE" | "PATCH" | "PUT";
    allowFail?: boolean;
    jsonData?: any;
    formData?: FormData;
  }): Promise<APIResponse> {
    let body = undefined;
    let headers: any = {
      "X-auth-token": AuthApi.SignedIn ? AuthApi.AuthToken : "none",
    };

    // JSON request
    if (args.jsonData) {
      headers["Content-Type"] = "application/json";
      body = JSON.stringify(args.jsonData);
    }

    // Form data request
    else if (args.formData) {
      body = args.formData;
    }

    const res = await fetch(this.backendURL() + args.uri, {
      method: args.method,
      body: body,
      headers: headers,
    });

    // Process response
    let data;
    if (res.headers.get("content-type") === "application/json")
      data = await res.json();
    else data = await res.blob();

    // Handle expired tokens
    if (res.status === 412) {
      AuthApi.RemoveAuthToken();
      window.location.href = "/";
    }

    if (!args.allowFail && !res.ok)
      throw new ApiError("Request failed!", res.status, data);

    return {
      data: data,
      status: res.status,
    };
  }
}
