import { defineStore } from 'pinia' import { computed, ref } from 'vue' import { authApi } from '@/api' import { mapApiUser } from '@/api/mappers' import { buildApiUrl, setApiAccessToken } from '@/api/client' import type { AuthResponse } from '@/api/types' import type { User } from '@/types' const TOKEN_STORAGE_KEY = 'universe.accessToken' const ACTIVE_ROLE_STORAGE_KEY = 'universe.activeRole' function restoreStoredActiveRole(mappedUser: User) { const storedRole = localStorage.getItem(ACTIVE_ROLE_STORAGE_KEY) as User['activeRole'] | null if (!storedRole || !mappedUser.roles.includes(storedRole)) return mappedUser return { ...mappedUser, activeRole: storedRole } } function applyAuthResponse(response: AuthResponse) { localStorage.setItem(TOKEN_STORAGE_KEY, response.accessToken) setApiAccessToken(response.accessToken) return restoreStoredActiveRole(mapApiUser(response.user)) } function getAuthReturnUrl() { return import.meta.env.VITE_AUTH_RETURN_URL || '/auth/callback' } function getAbsoluteAuthReturnUrl() { return new URL(getAuthReturnUrl(), window.location.origin).toString() } export const useAuthStore = defineStore('auth', () => { const user = ref(null) const loading = ref(false) const initialized = ref(false) const error = ref(null) const accessToken = ref(localStorage.getItem(TOKEN_STORAGE_KEY)) if (accessToken.value) setApiAccessToken(accessToken.value) const isAuthenticated = computed(() => Boolean(user.value && accessToken.value)) async function hydrateFromResponse(response: AuthResponse) { accessToken.value = response.accessToken user.value = applyAuthResponse(response) error.value = null } async function initialize() { if (initialized.value) return isAuthenticated.value loading.value = true error.value = null try { const refreshed = await authApi.refresh() await hydrateFromResponse(refreshed) const me = await authApi.me() user.value = restoreStoredActiveRole(mapApiUser(me)) return true } catch (refreshError) { if (accessToken.value) { try { const me = await authApi.me() user.value = restoreStoredActiveRole(mapApiUser(me)) return true } catch { // Fall through to local cleanup below. } } clearSession() error.value = refreshError instanceof Error ? refreshError.message : null return false } finally { initialized.value = true loading.value = false } } function startMicrosoftLogin() { window.location.assign(buildApiUrl('/auth/login/microsoft', { returnUrl: getAuthReturnUrl() })) return true } async function completeMicrosoftLogin(code: string, _state: string | null) { loading.value = true error.value = null try { const redirectUri = getAbsoluteAuthReturnUrl() const response = await authApi.loginMicrosoft(code, redirectUri) await hydrateFromResponse(response) initialized.value = true return true } catch (err) { clearSession() error.value = err instanceof Error ? err.message : 'Ошибка авторизации через Microsoft.' throw err } finally { loading.value = false } } async function completeTokenLogin(token: string) { loading.value = true error.value = null try { accessToken.value = token localStorage.setItem(TOKEN_STORAGE_KEY, token) setApiAccessToken(token) const me = await authApi.me() user.value = restoreStoredActiveRole(mapApiUser(me)) initialized.value = true return true } catch (err) { clearSession() error.value = err instanceof Error ? err.message : 'Не удалось получить пользователя после входа.' throw err } finally { loading.value = false } } async function logout() { loading.value = true try { await authApi.logout() } catch { // Local cleanup is still correct if the server session is already gone. } finally { clearSession() initialized.value = true loading.value = false } } function clearSession() { user.value = null accessToken.value = null localStorage.removeItem(TOKEN_STORAGE_KEY) localStorage.removeItem(ACTIVE_ROLE_STORAGE_KEY) setApiAccessToken(null) } function setUser(nextUser: User) { user.value = nextUser } function setActiveRole(role: User['activeRole']) { if (!user.value || !user.value.roles.includes(role)) return false localStorage.setItem(ACTIVE_ROLE_STORAGE_KEY, role) user.value = { ...user.value, activeRole: role } return true } return { user, accessToken, isAuthenticated, loading, initialized, error, initialize, startMicrosoftLogin, completeMicrosoftLogin, completeTokenLogin, logout, clearSession, setUser, setActiveRole, } })