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<User | null>(null)
  const loading = ref(false)
  const initialized = ref(false)
  const error = ref<string | null>(null)
  const accessToken = ref<string | null>(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,
  }
})
