import axios from "axios";

import { boot } from "quasar/wrappers";
import { Cookies, Notify } from "quasar";
import { useAuth } from "src/composables/useAuth";

const api = axios.create({
  baseURL: process.env.API_URL + "/api",
  withCredentials: true,
  withXSRFToken: true,
});

api.interceptors.request.use(
  async (config) => {
    const accessToken = Cookies.get("access_token");
    const savedLanguage = Cookies.get("locale");
    const language = savedLanguage || window.navigator.language;

    config.headers["Accept-Language"] = language;

    if (accessToken) {
      config.headers.Authorization = `Bearer ${accessToken}`;
    }

    return config;
  },
  (error) => {
    return Promise.reject(error);
  },
);

let isRefreshing = false;

let validQueue = [];

const errorInterceptor = async (error) => {
  if (error.config?.retryCount) {
    error.config.retryCount = 0;
  }

  if (error.config.retryCount >= 3) {
    return Promise.reject(error);
  }

  error.config.retryCount++;

  if (!error.response) {
    return Promise.reject(error);
  }

  if (error.response.status === 401) {
    const requestUrl = error?.config?.url ?? "";

    if (requestUrl.startsWith("/login")) {
      return Promise.reject(error);
    }

    if (isRefreshing) {
      return new Promise((resolve, reject) => {
        validQueue.push({ resolve, reject, config: error.config });
      });
    }

    isRefreshing = true;

    try {
      await useAuth().refreshToken();
    } catch (error) {
      validQueue = [];

      Cookies.remove("access_token");
      Cookies.remove("refresh_token");

      if (window.location.pathname !== "/login") {
        window.location.href = "/login";
      }

      return Promise.reject(error);
    }

    try {
      validQueue.forEach((request) => {
        request.resolve(api.request(request.config));
      });

      validQueue = [];

      return await api.request(error.config);
    } catch (error) {
      console.error(error);
    } finally {
      isRefreshing = false;
    }
  }

  return Promise.reject(error);
};

const successInterceptor = (response) => {
  if (response.data.message) {
    Notify.create({
      message: response.data.message,
      type: "positive",
    });
  }

  return response;
};

export default boot(({ app }) => {
  api.interceptors.response.use(
    (response) => successInterceptor(response),
    (error) => errorInterceptor(error),
  );

  // for use inside Vue files (Options API) through this.$axios and this.$api
  app.config.globalProperties.$axios = axios;
  // ^ ^ ^ this will allow you to use this.$axios (for Vue Options API form)
  //       so you won't necessarily have to import axios in each vue file

  app.config.globalProperties.$api = api;
  // ^ ^ ^ this will allow you to use this.$api (for Vue Options API form)
  //       so you can easily perform requests against your app's API
});

export { api };
