import { $fetchCitizen, $XCTN_TOKEN } from '~/utils/$fetchCitizen'

const LOGIN = '/employee/login-dashboard'
const LOGOUT = '/employee/logout'
const CURRENT_USER = '/employee/info'

interface CitizenLoginCredentials {
  login_id: string
  password: string
}

interface CitizenLoginResponse {
  status?: boolean
  message?: string
  data?: {
    token?: string
    user?: unknown
  }
}

interface ApiError {
  response?: {
    status?: number
  }
}

// State has three meanings: undefined = auth not checked, null = anonymous,
// object = authenticated employee. The boot plugin resolves the first state.
export const citizenUser = () => useState<unknown | null | undefined>('citizen_user', () => undefined)

export const fetchCitizenCurrentUser = async () => {
  try {
    return await $fetchCitizen<unknown>('/v2/employee/info', { method: 'GET' }).catch(async () => {
      return await $fetchCitizen<unknown>(CURRENT_USER, { method: 'GET' })
    })
  } catch (error) {
    const status = (error as ApiError).response?.status

    // These statuses represent an unusable session, not an application crash.
    // Returning null lets the plugin clear the stale token and continue safely.
    if (status && [400, 401, 419].includes(status)) return null

    throw error
  }
}

export const citizenAuth = () => {
  const citizen_user = citizenUser()
  const isCitizenLoggedIn = computed(() => Boolean(citizen_user.value))
  const token = useCookie<string | null>($XCTN_TOKEN)
  const isLoadingLogout = ref(false)

  const login = async (credentials: CitizenLoginCredentials) => {
    if (isCitizenLoggedIn.value) return

    const response = await $fetchCitizen<CitizenLoginResponse>(LOGIN, {
      method: 'POST',
      body: credentials
    })

    if (!response.data?.token) return response

    // Store the token before requesting /employee/info because the shared wrapper
    // reads this cookie to construct the Bearer header.
    token.value = response.data.token

    try {
      // Some login responses already contain the user; otherwise hydrate it with
      // the canonical current-user endpoint before any protected navigation.
      citizen_user.value = response.data.user ?? await fetchCitizenCurrentUser()
    } catch (error) {
      // Avoid leaving a half-authenticated cookie if user hydration fails.
      token.value = null
      throw error
    }

    return response
  }

  const logout = async () => {
    if (!isCitizenLoggedIn.value || isLoadingLogout.value) return

    isLoadingLogout.value = true

    try {
      await $fetchCitizen(LOGOUT, { method: 'GET' })
    } finally {
      // Local cleanup must happen even if the logout endpoint is unavailable;
      // otherwise the UI could remain trapped in a stale authenticated state.
      citizen_user.value = null
      token.value = null
      isLoadingLogout.value = false
      await navigateTo('/login')
    }
  }

  return {
    citizen_user,
    isCitizenLoggedIn,
    isLoadingLogout,
    login,
    logout
  }
}
