import axios from 'axios';
import { store } from '../store';
import { logout } from '../features/auth/authSlice';

const unauthorizedCode = [1007, 401];
const deviceId = 'WEB_123';
const deviceType = 'web';

let isRefreshing = false; // Track if token refresh is in progress
let refreshTokenPromise: Promise<string | null> | null = null; // Store the refresh token promise
let refreshSubscribers: ((token: string) => void)[] = [];

const api = axios.create({
    baseURL: process.env.NEXT_PUBLIC_API_URL,
    headers: {
        'Content-Type': 'application/json',
    },
});

const logoutUser = () => {
    store.dispatch(logout());

    // Redirect to login page if we're in the browser
    if (typeof window !== 'undefined') {
        window.location.href = '/login';
    }
};

const onRefreshed = (token: string) => {
    refreshSubscribers.forEach((cb) => cb(token));
    refreshSubscribers = [];
};

const subscribeTokenRefresh = (cb: (token: string) => void) => {
    refreshSubscribers.push(cb);
};

const refreshAccessToken = async (): Promise<string | null> => {
    try {
        const currentState = store.getState();
        const currentToken = currentState?.auth?.accessToken || '';

        // Add Bearer prefix if not already present
        const token = currentToken.startsWith('Bearer ') ? currentToken : `Bearer ${currentToken}`;

        const response = await axios.post(
            `${process.env.NEXT_PUBLIC_API_URL}/auth/refresh-token`,
            {
                device_id: deviceId,
            },
            {
                headers: {
                    Authorization: token,
                },
            },
        );

        if (!response?.data?.success) {
            logoutUser();
            return null;
        }

        const newAccessToken = response?.data?.data?.access_token;

        // Dispatch the new token to the Redux store
        store.dispatch({
            type: 'auth/saveUserDetails',
            payload: {
                accessToken: newAccessToken,
                user: currentState.auth.user,
            },
        });

        return newAccessToken;
    } catch (error) {
        logoutUser();
        return null;
    }
};

api.interceptors.request.use(
    (config) => {
        const persistData = store.getState();

        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        let accessToken = (persistData as any)?.auth?.accessToken;

        if (!accessToken) {
            const { auth } = store.getState();
            accessToken = auth.accessToken;
            config.headers.device_id = deviceId;
            config.headers.device_type = deviceType;
        }

        if (accessToken) {
            // Add Bearer prefix if not already present
            const token = accessToken.startsWith('Bearer ') ? accessToken : `Bearer ${accessToken}`;
            config.headers.Authorization = token;
            config.headers.device_id = deviceId;
            config.headers.device_type = deviceType;
        } else {
            console.warn('API Request without token:', config.method?.toUpperCase(), config.url);
        }

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

api.interceptors.response.use(
    (response) => response,
    async (error) => {
        const { response } = error;

        const code = response?.data?.code ?? null;

        if (response?.data?.success === false && unauthorizedCode.includes(response.status || code)) {
            const originalRequest = error.config;

            if (!isRefreshing) {
                isRefreshing = true;
                refreshTokenPromise = refreshAccessToken();

                refreshTokenPromise.then((newToken) => {
                    isRefreshing = false;
                    refreshTokenPromise = null;
                    if (newToken) onRefreshed(newToken);
                });
            }

            const token = await new Promise<string | null>((resolve) => {
                subscribeTokenRefresh((newToken) => {
                    resolve(newToken);
                });
            });

            if (token) {
                // Add Bearer prefix if not already present
                const authToken = token.startsWith('Bearer ') ? token : `Bearer ${token}`;
                originalRequest.headers['Authorization'] = authToken;
                return axios(originalRequest);
            }
        }

        return Promise.reject(error);
    },
);

export default api;
