import { boot } from 'quasar/wrappers';
import type { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
import axios from 'axios';
import { useLogin } from 'src/vueLib/login/useLogin';

const host = window.location.hostname;
export const portApp = 9500;

// Create axios instance
export const appApi: AxiosInstance = axios.create({
  baseURL: `https://${host}:${portApp}/api`,
  timeout: 10000,
  withCredentials: true,
});

interface RetryRequestConfig extends AxiosRequestConfig {
  _retry?: boolean;
}

const noRefreshEndpoints = ['/login', '/secure/login/refresh', '/logout'];

// ========= Refresh Queue Handling ========= //
let isRefreshing = false;

interface FailedRequest {
  resolve: (value?: unknown) => void;
  reject: (reason?: Error) => void;
}

let failedQueue: FailedRequest[] = [];

const processQueue = (error: Error | null): void => {
  failedQueue.forEach((prom) => {
    if (error) prom.reject(error);
    else prom.resolve();
  });
  failedQueue = [];
};
// ========================================= //

appApi.interceptors.response.use(
  (response: AxiosResponse) => response,

  async (error: AxiosError<unknown, RetryRequestConfig>): Promise<AxiosResponse> => {
    const { refresh, logout } = useLogin();
    const originalRequest = error.config as RetryRequestConfig | undefined;

    // Skip refresh for login/logout endpoints
    if (
      !originalRequest ||
      noRefreshEndpoints.some((url) => originalRequest.url?.includes(url ?? ''))
    ) {
      const message = error instanceof Error ? error.message : JSON.stringify(error);
      throw new Error(message);
    }

    // Handle unauthorized responses
    if (error.response?.status === 401 && !originalRequest._retry) {
      if (isRefreshing) {
        // Wait until refresh completes
        return new Promise<AxiosResponse>((resolve, reject) => {
          failedQueue.push({
            resolve: () => {
              void appApi(originalRequest).then(resolve).catch(reject);
            },
            reject,
          });
        });
      }

      originalRequest._retry = true;
      isRefreshing = true;

      try {
        const refreshed = await refresh().catch(() => false);
        processQueue(null);

        if (refreshed) {
          // Token refreshed successfully → retry request
          return appApi(originalRequest);
        }

        // Refresh returned false → logout
        console.warn('[Axios] Refresh returned false, logging out');
        await logout();
        throw new Error('Token refresh failed');
      } catch (err) {
        const e = err instanceof Error ? err : new Error(String(err));
        console.error('[Axios] Token refresh failed:', e.message);

        // Always logout, even if refresh throws
        try {
          await logout();
        } catch (logoutErr) {
          console.error('[Axios] Logout failed after token refresh error:', logoutErr);
        }

        processQueue(e);
        throw e;
      } finally {
        isRefreshing = false;
      }
    }

    // Not a 401 — rethrow as Error

    let msg = '';
    if (error && (error as AxiosError).isAxiosError) {
      const axiosError = error as AxiosError<{ message?: string }>;
      msg = axiosError.response?.data?.message ?? axiosError.message;
    } else {
      msg = error instanceof Error ? error.message : JSON.stringify(error);
    }

    throw new Error(msg);
  },
);

// ======== Boot registration for Quasar ======== //
export default boot(({ app }) => {
  app.config.globalProperties.$axios = axios;
  app.config.globalProperties.$appApi = appApi;
});

export { axios };
