// hooks/useAuth.ts

import {
  AUTH_INFO_KEY,
  AUTH_REFRESH_FAILED_EVENT,
} from '@/constants/system'
import { useRouter } from '@/i18n/navigation'
import { BaseAPIResponse } from '@/models/api/common'
import { useGetUrlLoginMutation } from '@/share/layout/end-user/header/hook'
import { useMutation, useQuery } from '@tanstack/react-query'
import { AxiosError } from 'axios'
import { useCallback } from 'react'
import {
  AuthInfoBase,
  AuthInfoBaseResponse,
  AuthInfoFullSchema,
  LogoutRequest,
} from './auth.schema'
import authApi from './auth.service'

export const authKeys = {
  all: ['auth'] as const,
  verifyToken: (token?: string) =>
    [...authKeys.all, token, 'verifyToken'] as const,
  parseToken: (token: string) =>
    [...authKeys.all, token, 'parseToken'] as const,
}

export function useVerifyToken(token: string) {
  return useQuery({
    queryKey: authKeys.verifyToken(token),
    queryFn: () => authApi.verifyToken(token),
    retry: false,
  })
}

export function useParseToken(token: string) {
  return useQuery({
    queryKey: authKeys.parseToken(token),
    queryFn: () => authApi.parseToken(token),
    retry: false,
  })
}

const clearAuthAndLogout = () => {
  localStorage.removeItem(AUTH_INFO_KEY)
}

export const useRefresh = (
  onSuccessCallback: (data: AuthInfoBase) => void,
  onErrorCallback: () => void
) => {
  return useMutation<
    AuthInfoBaseResponse,
    AxiosError
  >({
    mutationFn: () => authApi.refresh(),
    onSuccess: (data) => onSuccessCallback(data.data),
    onError: () => {
      clearAuthAndLogout()
      onErrorCallback()
    },
  })
}
export const useLogout = (onSuccess: () => void) => {
  const mutate = useGetUrlLoginMutation()
  return useMutation<BaseAPIResponse, AxiosError, LogoutRequest>({
    mutationFn: (body) => authApi.logout(body),
    onSuccess: () => {
      onSuccess()
      mutate.mutate()
    },
  })
}

export const useTokenRefresh = () => {
  const router = useRouter()
  const refreshToken = useCallback(async (): Promise<AuthInfoBaseResponse> => {
    const savedAuthInfoLocal = localStorage.getItem(AUTH_INFO_KEY)
    if (!savedAuthInfoLocal) {
      throw new Error('Cannot find auth information to refresh')
    }
    const authInfo = JSON.parse(savedAuthInfoLocal)

    try {
      const newAuthInfo = await authApi.refresh()
      const newAuthInfoFull = AuthInfoFullSchema.parse({
        ...newAuthInfo.data,
        user_info: authInfo.user_info,
      })
      localStorage.setItem(AUTH_INFO_KEY, JSON.stringify(newAuthInfoFull))
      return newAuthInfo
    } catch (e) {
      if (
        e instanceof AxiosError &&
        e.response?.status === 401 &&
        typeof window !== 'undefined'
      ) {
        window.dispatchEvent(new CustomEvent(AUTH_REFRESH_FAILED_EVENT))
      }
      throw e
    }
  }, [])

  const refreshTokenWithRetry = useCallback(
    async (onSuccess?: () => void) => {
      try {
        await refreshToken()
        onSuccess?.()
      } catch (refreshError) {
        clearAuthAndLogout()
        throw refreshError
      }
    },
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [router]
  )

  return {
    refreshToken,
    refreshTokenWithRetry,
    clearAuthAndLogout,
  }
}
