import { computed, ref } from 'vue'
import { defineStore } from 'pinia'

import { apiRequest, clearAccessToken, setAccessToken, setRefreshHandler } from '../api'

export const useAuthStore = defineStore('auth', () => {
  const user = ref(null)
  const accessToken = ref('')
  const status = ref('idle')

  const isAuthenticated = computed(() => Boolean(accessToken.value))

  function applyAccessToken(token) {
    accessToken.value = token || ''
    setAccessToken(accessToken.value)
  }

  function clearSession() {
    user.value = null
    accessToken.value = ''
    clearAccessToken()
  }

  async function refresh() {
    status.value = 'loading'

    try {
      const data = await apiRequest('/auth/refresh', {
        method: 'POST',
        skipAuth: true,
        skipRefresh: true,
      })

      const token = data?.accessToken || ''
      if (!token) {
        clearSession()
        status.value = 'idle'
        return false
      }

      applyAccessToken(token)
      status.value = 'idle'
      return true
    } catch {
      clearSession()
      status.value = 'idle'
      return false
    }
  }

  async function fetchMe() {
    try {
      const data = await apiRequest('/me', { method: 'GET' })
      user.value = data?.user || data || null
      return user.value
    } catch {
      user.value = null
      return null
    }
  }

  async function bootstrap() {
    // Try to restore session using refresh cookie.
    const ok = await refresh()
    if (ok) {
      await fetchMe()
    }
  }

  async function login({ email, password }) {
    status.value = 'loading'
    try {
      const data = await apiRequest('/auth/login', {
        method: 'POST',
        skipAuth: true,
        body: { email, password },
      })

      applyAccessToken(data?.accessToken || '')
      user.value = data?.user || null

      status.value = 'idle'
      return true
    } catch (err) {
      clearSession()
      status.value = 'error'
      throw err
    }
  }

  async function signup({ email, password, name }) {
    status.value = 'loading'
    try {
      const data = await apiRequest('/auth/signup', {
        method: 'POST',
        skipAuth: true,
        body: { email, password, name },
      })

      applyAccessToken(data?.accessToken || '')
      user.value = data?.user || null

      status.value = 'idle'
      return true
    } catch (err) {
      clearSession()
      status.value = 'error'
      throw err
    }
  }

  async function logout() {
    status.value = 'loading'
    try {
      await apiRequest('/auth/logout', { method: 'POST', skipRefresh: true })
    } finally {
      clearSession()
      status.value = 'idle'
    }
  }

  // Allow apiRequest() to refresh tokens automatically on 401.
  setRefreshHandler(async () => {
    const data = await apiRequest('/auth/refresh', {
      method: 'POST',
      skipAuth: true,
      skipRefresh: true,
    })

    const token = data?.accessToken || ''
    applyAccessToken(token)
    return token
  })

  // Keep api module token in sync if a token was already set.
  setAccessToken(accessToken.value)

  return {
    user,
    accessToken,
    status,
    isAuthenticated,
    bootstrap,
    fetchMe,
    refresh,
    login,
    signup,
    logout,
    clearSession,
  }
})
