import Axios from "axios";
import { ContextOptions, KeyValuePair } from "../components/context"

export async function Get(context: ContextOptions, url: string, params?: any) {
  const baseURL = await getBaseUrl(context);
  const headers = await getRequestHeaders(context);
  const paramsToSend = await buildQueryParams(context, params);

  let response;
  try {
    response = await Axios.get(url, {
      baseURL,
      params: paramsToSend,
      headers,
    })
  } catch (e) {
    console.error(`Failed to fetch url - ${url} - `, e)
    throw e
  }

  return response.data;
}

export async function Post(context: ContextOptions, url: string, body?: any, params?: any) {
  const baseURL = await getBaseUrl(context);
  const headers = await getRequestHeaders(context);
  const paramsToSend = await buildQueryParams(context, params);

  let response;
  try {
    response = await Axios.post(url, body, {
      baseURL,
      params: paramsToSend,
      headers,
    })
  } catch (e) {
    console.error(`Failed to fetch url - ${url} - `, e)
    throw e
  }

  return response.data;
}

export async function Download(context: ContextOptions, url: string, body?: any, params?: any) {
  const baseURL = await getBaseUrl(context);
  const headers = await getRequestHeaders(context);
  const paramsToSend = await buildQueryParams(context, params);

  let response;
  try {
    response = await Axios.post(url, body, {
      baseURL,
      params: paramsToSend,
      responseType: 'blob',
      headers,
    })
  } catch (e) {
    console.error(`Failed to fetch url - ${url} - `, e)
    throw e
  }

  return response.data;
}

export async function Put(context: ContextOptions, url: string, body?: any, params?: any) {
  const baseURL = await getBaseUrl(context);
  const headers = await getRequestHeaders(context);
  const paramsToSend = await buildQueryParams(context, params);

  let response;
  try {
    response = await Axios.put(url, body, {
      baseURL,
      params: paramsToSend,
      headers,
    })
  } catch (e) {
    console.error(`Failed to fetch url - ${url} - `, e)
    throw e
  }

  return response.data;
}

export async function Delete(context: ContextOptions, url: string, params?: any) {
  const baseURL = await getBaseUrl(context);
  const headers = await getRequestHeaders(context);
  const paramsToSend = await buildQueryParams(context, params);

  let response;
  try {
    response = await Axios.delete(url, {
      baseURL,
      params: paramsToSend,
      headers,
    })
  } catch (e) {
    console.error(`Failed to fetch url - ${url} - `, e)
    throw e
  }

  return response.data;
}

async function buildQueryParams(context: ContextOptions, params?: any) {
  if (!params) {
    params = {}
  }

  const additionalQueryParams = await getAdditionalQueryParams(context);
  for (const queryParam of additionalQueryParams) {
    params[queryParam.key] = queryParam.value;
  }

  return params;
}

async function getAdditionalQueryParams(context: ContextOptions): Promise<KeyValuePair[]> {
  let output = [];
  if (context.additionalQueryParamsResolver) {
    output = await context.additionalQueryParamsResolver();
  }

  return output;
}

async function getAdditionalHeaders(context: ContextOptions): Promise<KeyValuePair[]> {
  let output = [];
  if (context.additionalHeadersResolver) {
    output = await context.additionalHeadersResolver();
  }

  return output;
}

function getBaseUrl(context: ContextOptions): string {
  let baseUrl = context.baseUrl;
  // Append everything we need to the base url
  if (!baseUrl.endsWith('/')) { baseUrl += '/' }
  if (!baseUrl.endsWith('frontegg')) { baseUrl += 'frontegg' }

  return baseUrl
}

async function getRequestHeaders(context: ContextOptions) {
  const authToken = await context.tokenResolver();
  const headers = { 'Authorization': `Bearer ${authToken}` };

  const additionalHeaders = await getAdditionalHeaders(context);
  for (const additionalHeader of additionalHeaders) {
    headers[additionalHeader.key] = additionalHeader.value;
  }

  return headers;
}