import { defineBoot } from "#q-app/wrappers";
import { Cookies, Notify } from "quasar";
import axios from "axios";
import { userStore } from "src/stores/user";
import { i18n } from "src/boot/i18n";

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

api.interceptors.request.use(
  async (config) => {
    const accessToken = userStore().accessToken;
    const savedLanguage = Cookies.get("locale");
    const language = savedLanguage || window.navigator.language;
    config.headers["Accept-Language"] = language;
    config.headers["X-App-Origin"] = process.env.APP_NAME;
    if (accessToken) {
      config.headers.Authorization = `Bearer ${accessToken}`;
    }
    return config;
  },
  (error) => {
    return Promise.reject(error);
  },
);

let isRefreshing = false;
let failedQueue = [];

const processQueue = (error, token = null) => {
  failedQueue.forEach((prom) => {
    if (error) {
      prom.reject(error);
    } else {
      prom.config.headers["Authorization"] = "Bearer " + token;
      prom.resolve(api(prom.config));
    }
  });
  failedQueue = [];
};

const errorInterceptor = async (error, router) => {
  const originalRequest = error.config;
  const user_store = userStore();

  if (error.response?.status === 422) {
    return Promise.reject(error);
  }

  if (error.response?.status === 413) {
    Notify.create({
      message: i18n.global.t("http.errors.413"),
      type: "negative",
    });
    return Promise.reject(error);
  }

  if (
    error.response?.status !== 401 ||
    originalRequest.url.includes("/refresh")
  ) {
    if (error?.response?.data?.message) {
      Notify.create({
        message: error?.response?.data?.message,
        type: "negative",
      });
    }
    return Promise.reject(error);
  }

  if (error?.config?.url === "/login") {
    if (error?.response?.data?.message) {
      Notify.create({
        message: error?.response?.data?.message,
        type: "negative",
      });
    }
    return Promise.reject(error);
  }

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

  isRefreshing = true;
  try {
    const response = await api.post("/refresh");
    const newAccessToken = response.data.payload.access_token;
    user_store.accessToken = newAccessToken;
    originalRequest.headers["Authorization"] = `Bearer ${newAccessToken}`;
    processQueue(null, newAccessToken);
    return api(originalRequest);
  } catch (err) {
    processQueue(err, null);
    user_store.resetUser();
    router.push("/login");
    return Promise.reject(err);
  } finally {
    isRefreshing = false;
  }
};

const successInterceptor = (response) => {
  // skipSuccessNotify: a tela cuida da mensagem, evitando avisos duplicados em fluxos encadeados.
  if (response?.data?.message && !response.config?.skipSuccessNotify) {
    Notify.create({
      message: response?.data?.message,
      type: "positive",
    });
  }
  return response;
};

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

  // 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 };
