let refreshPromise = null;

const AUTH_KEYS = ['token', 'role', 'departmentId', 'userId'];

export function getToken() {
    return localStorage.getItem('token');
}

export function isAuthenticatedAsAdmin() {
    const role = localStorage.getItem('role');
    return getToken() && role === 'ADMIN';
}

export function isAuthenticatedAsRole(expectedRole) {
    const role = localStorage.getItem('role');
    return getToken() && role === expectedRole;
}

export function isAuthenticatedAsAny(roles) {
    const role = localStorage.getItem('role');
    return getToken() && roles.includes(role);
}

function getHeaders(contentType = 'application/json') {
    const headers = {};
    const token = getToken();
    if (token) {
        headers.Authorization = `Bearer ${token}`;
    }
    if (contentType) {
        headers['Content-Type'] = contentType;
    }
    return headers;
}

export async function apiFetch(endpoint, method = 'GET', body = null, retryOnUnauthorized = true) {
    const options = {
        method,
        headers: getHeaders(body ? 'application/json' : null),
        credentials: 'same-origin'
    };

    if (body) {
        options.body = JSON.stringify(body);
    }

    const response = await fetch(endpoint, options);

    let data;
    try {
        data = await response.json();
    } catch (e) {
        data = null;
    }

    if (response.status === 401 && retryOnUnauthorized) {
        const refreshed = await refreshAccessToken();
        if (refreshed) {
            return apiFetch(endpoint, method, body, false);
        }
        clearAuthState();
        window.location.href = '/';
    }

    if (!response.ok) {
        const error = new Error(data?.message || `Ошибка HTTP: ${response.status}`);
        error.status = response.status;
        error.data = data;
        throw error;
    }

    return data;
}

export async function refreshAccessToken() {
    if (refreshPromise) {
        return refreshPromise;
    }

    refreshPromise = (async () => {
        const response = await fetch('/api/auth/refresh', {
            method: 'POST',
            credentials: 'same-origin'
        });
        const data = await response.json().catch(() => null);
        if (!response.ok || !data?.token) {
            return false;
        }
        storeAuthState(data);
        return true;
    })().finally(() => {
        refreshPromise = null;
    });

    return refreshPromise;
}

const cache = new Map();

const CACHABLE_PREFIXES = [
    '/api/departments',
    '/api/specialties',
    '/api/education-forms',
    '/api/users/teachers',
    '/api/equipments',
    '/api/classrooms'
];

function invalidateCache(url) {
    const cacheKeysToClear = [
        '/api/departments',
        '/api/specialties',
        '/api/education-forms',
        '/api/users',
        '/api/teacher-requests',
        '/api/department/teacher-requests',
        '/api/department/teachers',
        '/api/equipments',
        '/api/classrooms'
    ];
    const affectedPrefixes = new Set(cacheKeysToClear.filter(prefix => url.includes(prefix)));
    if (url.includes('/api/teacher-requests')) {
        affectedPrefixes.add('/api/users');
    }
    if (url.includes('/api/department/teachers')) {
        affectedPrefixes.add('/api/users/teachers');
    }
    for (const prefix of affectedPrefixes) {
        for (const cacheKey of cache.keys()) {
            if (cacheKey.includes(prefix)) {
                cache.delete(cacheKey);
            }
        }
    }
}

export function clearCache() {
    cache.clear();
}

export async function logout() {
    try {
        await fetch('/api/auth/logout', {
            method: 'POST',
            credentials: 'same-origin'
        });
    } catch (e) {
        console.warn('Не удалось завершить серверную сессию:', e.message);
    } finally {
        clearAuthState();
        clearCache();
    }
}

export function storeAuthState(data) {
    if (data.token) localStorage.setItem('token', data.token);
    if (data.role) localStorage.setItem('role', data.role);
    if (data.departmentId !== undefined && data.departmentId !== null) {
        localStorage.setItem('departmentId', data.departmentId);
    }
    if (data.userId !== undefined && data.userId !== null) {
        localStorage.setItem('userId', data.userId);
    }
}

export function clearAuthState() {
    AUTH_KEYS.forEach(key => localStorage.removeItem(key));
}

export const api = {
    get: async (url) => {
        const isCachable = CACHABLE_PREFIXES.some(prefix => url.startsWith(prefix));
        if (isCachable) {
            if (!cache.has(url)) {
                cache.set(url, await apiFetch(url, 'GET'));
            }
            return cache.get(url);
        }
        return apiFetch(url, 'GET');
    },
    post: async (url, body) => {
        invalidateCache(url);
        return apiFetch(url, 'POST', body);
    },
    put: async (url, body) => {
        invalidateCache(url);
        return apiFetch(url, 'PUT', body);
    },
    delete: async (url, body = null) => {
        invalidateCache(url);
        return apiFetch(url, 'DELETE', body);
    }
};
