import axios, { AxiosRequestConfig } from 'axios';
export { AxiosInstance as IHttpClient } from 'axios';
import { IHttpClientParams } from '@automatisch/types';
import { URL } from 'url';
import HttpError from '../../errors/http';

const removeBaseUrlForAbsoluteUrls = (
  requestConfig: AxiosRequestConfig
): AxiosRequestConfig => {
  try {
    const url = new URL(requestConfig.url);
    requestConfig.baseURL = url.origin;
    requestConfig.url = url.pathname + url.search;

    return requestConfig;
  } catch {
    return requestConfig;
  }
};

export default function createHttpClient({
  $,
  baseURL,
  beforeRequest = [],
}: IHttpClientParams) {
  const instance = axios.create({
    baseURL,
  });

  instance.interceptors.request.use(
    (requestConfig: AxiosRequestConfig): AxiosRequestConfig => {
      const newRequestConfig = removeBaseUrlForAbsoluteUrls(requestConfig);

      return beforeRequest.reduce((newConfig, beforeRequestFunc) => {
        return beforeRequestFunc($, newConfig);
      }, newRequestConfig);
    }
  );

  instance.interceptors.response.use(
    (response) => response,
    async (error) => {
      const { config } = error;
      const { status } = error.response;

      if (
        status === 401 &&
        $.app.auth.refreshToken &&
        !$.app.auth.isRefreshTokenRequested
      ) {
        $.app.auth.isRefreshTokenRequested = true;
        await $.app.auth.refreshToken($);

        // retry the previous request before the expired token error
        const newResponse = await instance.request(config);
        $.app.auth.isRefreshTokenRequested = false;

        return newResponse;
      }

      throw new HttpError(error);
    }
  );

  return instance;
}
