import axios from 'axios';
import AsyncLock from 'async-lock';
import { getEnv } from './read-env-config';
import { COOKIE_REFRESH_TOKEN, COOKIE_SESSION_SIGN_IN, loginPage } from './utils/constants';
import saveCookiesClient from './components/Func/saveCookiesClient';
import PHXFuncGetCookieSession from './components/Func/getCookieSession';
import { clearSession } from './components/Func/sessionStore';
import Cookies from 'js-cookie';
import { deleteLocalStorage } from './components/Func/save-local-storage';
const lock = new AsyncLock();
const isServer = typeof window === 'undefined';
const publicUrl = getEnv('NEXT_PUBLIC_API_GATEWAY', process.env.NEXT_PUBLIC_API_GATEWAY);
const internalUrl = getEnv('NEXT_PUBLIC_API_GATEWAY_INTERNAL', process.env.NEXT_PUBLIC_API_GATEWAY_INTERNAL);
const PHXAxiosInstance = axios.create({
    baseURL: publicUrl,
});
// === GLOBAL CACHE ===
let accessTokenCache = null;
let refreshingPromise = null;
// Hàm refresh access token, chỉ gọi 1 lần duy nhất tại một thời điểm
const refreshAccessToken = async () => {
    if (!refreshingPromise) {
        refreshingPromise = lock.acquire(COOKIE_REFRESH_TOKEN, async () => {
            try {
                const url = `/api/authenticate/refresh-token`;
                const response = await axios.post(url, {});
                const newToken = response.data.token;
                const currentSession = PHXFuncGetCookieSession();
                // Lưu lại vào cookie phía client
                currentSession === null || currentSession === void 0 ? true : delete currentSession.access_token;
                // vì chuyển đổi sang lưu vào local storage nên phải xóa cookie
                Cookies.remove(COOKIE_SESSION_SIGN_IN);
                saveCookiesClient({ value: { ...currentSession, access_token: newToken } });
                // Cập nhật cache
                accessTokenCache = newToken;
                return newToken;
            }
            catch (err) {
                clearSession();
                Cookies.remove(COOKIE_SESSION_SIGN_IN);
                deleteLocalStorage(COOKIE_SESSION_SIGN_IN);
                if (!isServer) {
                    window.location.href = loginPage;
                }
                throw err;
            }
            finally {
                refreshingPromise = null;
            }
        });
    }
    return refreshingPromise;
};
// Request interceptor: luôn thêm Authorization nếu có access_token
PHXAxiosInstance.interceptors.request.use(async (config) => {
    var _a;
    config.headers = config.headers || {};
    // Ưu tiên lấy token từ cache
    let token = accessTokenCache;
    if (!token) {
        const session = PHXFuncGetCookieSession();
        token = (session === null || session === void 0 ? void 0 : session.access_token) || null;
        if (token)
            accessTokenCache = token;
    }
    if (token) {
        config.headers.Authorization = `Bearer ${token}`;
        // Nếu đang SSR, validate trước
        if (isServer) {
            try {
                await axios.post(`${internalUrl}/authen/authenticate`, {}, { headers: { Authorization: `Bearer ${token}` } });
            }
            catch (err) {
                if (((_a = err.response) === null || _a === void 0 ? void 0 : _a.status) === 401) {
                    const fresh = await refreshAccessToken();
                    config.headers.Authorization = `Bearer ${fresh}`;
                }
                else {
                    throw err;
                }
            }
        }
    }
    return config;
});
// Response interceptor: bắt lỗi 401, gọi refresh và retry
PHXAxiosInstance.interceptors.response.use((res) => res, async (error) => {
    var _a;
    const originalRequest = error.config;
    if (((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 401 && !originalRequest._retry) {
        originalRequest._retry = true;
        try {
            const newToken = await refreshAccessToken();
            originalRequest.headers = originalRequest.headers || {};
            originalRequest.headers.Authorization = `Bearer ${newToken}`;
            return PHXAxiosInstance(originalRequest);
        }
        catch (e) {
            return Promise.reject(e);
        }
    }
    return Promise.reject(error);
});
export { PHXAxiosInstance };
//# sourceMappingURL=axiosInstance.js.map