import { useSession, signIn, signOut } from 'next-auth/react'
import { useCallback, useMemo } from 'react'
import { AuthUser, UserRole } from './types'
import { hasPermission, hasRole, hasAnyPermission, hasAllPermissions } from './permissions'

interface UseAuthReturn {
  // User state
  user: AuthUser | null
  isAuthenticated: boolean
  isLoading: boolean

  // Auth actions
  login: (provider?: string, options?: { callbackUrl?: string }) => Promise<void>
  logout: (options?: { callbackUrl?: string }) => Promise<void>
  loginWithCredentials: (email: string, password: string, callbackUrl?: string) => Promise<void>

  // Permission checks
  can: (permission: string) => boolean
  canAny: (permissions: string[]) => boolean
  canAll: (permissions: string[]) => boolean
  is: (role: UserRole) => boolean
  isAtLeast: (role: UserRole) => boolean

  // Session management
  refreshSession: () => Promise<void>
}

export function useAuth(): UseAuthReturn {
  const { data: session, status, update } = useSession()
  const isLoading = status === 'loading'
  const isAuthenticated = status === 'authenticated'

  const user: AuthUser | null = useMemo(() => {
    if (!session?.user) return null
    return {
      id: session.user.id,
      email: session.user.email!,
      name: session.user.name,
      image: session.user.image,
      role: session.user.role || UserRole.USER,
      emailVerified: session.user.emailVerified,
    }
  }, [session])

  const login = useCallback(
    async (provider?: string, options?: { callbackUrl?: string }) => {
      await signIn(provider, { callbackUrl: options?.callbackUrl || '/' })
    },
    []
  )

  const logout = useCallback(async (options?: { callbackUrl?: string }) => {
    await signOut({ callbackUrl: options?.callbackUrl || '/' })
  }, [])

  const loginWithCredentials = useCallback(
    async (email: string, password: string, callbackUrl?: string) => {
      const result = await signIn('credentials', {
        email,
        password,
        redirect: false,
      })

      if (result?.error) {
        throw new Error(result.error)
      }

      if (callbackUrl) {
        window.location.href = callbackUrl
      }
    },
    []
  )

  const can = useCallback(
    (permission: string): boolean => {
      if (!user) return false
      return hasPermission(user.role, permission)
    },
    [user]
  )

  const canAny = useCallback(
    (permissions: string[]): boolean => {
      if (!user) return false
      return hasAnyPermission(user.role, permissions)
    },
    [user]
  )

  const canAll = useCallback(
    (permissions: string[]): boolean => {
      if (!user) return false
      return hasAllPermissions(user.role, permissions)
    },
    [user]
  )

  const is = useCallback(
    (role: UserRole): boolean => {
      if (!user) return false
      return user.role === role
    },
    [user]
  )

  const isAtLeast = useCallback(
    (role: UserRole): boolean => {
      if (!user) return false
      return hasRole(user.role, role)
    },
    [user]
  )

  const refreshSession = useCallback(async () => {
    await update()
  }, [update])

  return {
    user,
    isAuthenticated,
    isLoading,
    login,
    logout,
    loginWithCredentials,
    can,
    canAny,
    canAll,
    is,
    isAtLeast,
    refreshSession,
  }
}

// Hook for checking a specific permission
export function usePermission(permission: string): boolean {
  const { can } = useAuth()
  return can(permission)
}

// Hook for checking a specific role
export function useRole(role: UserRole): boolean {
  const { isAtLeast } = useAuth()
  return isAtLeast(role)
}

// Hook for requiring authentication (with redirect)
export function useRequireAuth(options?: { redirectTo?: string }) {
  const { isAuthenticated, isLoading } = useAuth()

  if (!isLoading && !isAuthenticated && typeof window !== 'undefined') {
    const redirectTo = options?.redirectTo || '/auth/signin'
    window.location.href = `${redirectTo}?callbackUrl=${encodeURIComponent(window.location.pathname)}`
  }

  return { isAuthenticated, isLoading }
}
