import {
  useContext,
  useMemo,
  useCallback,
  createContext,
  useState,
} from 'react'
import * as Auth from 'aws-amplify/auth'

interface AuthContextType {
  authUser: Auth.FetchUserAttributesOutput | null
  signIn: ({
    username,
    password,
  }: {
    username: string
    password: string
  }) => Promise<Auth.SignInOutput>
  currentUser: () => Promise<Auth.FetchUserAttributesOutput | void>
}

const AuthContext = createContext<AuthContextType | null>(null)

export function useAuth() {
  return useContext(AuthContext)
}

export function AuthProvider({ children }: { children: React.ReactNode }) {
  const [authUser, setAuthUser] =
    useState<Auth.FetchUserAttributesOutput | null>(null)

  const currentUser = useCallback(async () => {
    try {
      const currentUser = await Auth.fetchUserAttributes()

      setAuthUser(currentUser)
      return currentUser
    } catch {
      setAuthUser(null)
    }
  }, [])

  const signIn = useCallback(
    async ({
      username,
      password,
    }: {
      username: string
      password: string
    }): Promise<Auth.SignInOutput> => {
      const signInOut = await Auth.signIn({
        username,
        password,
        options: {
          clientMetadata: {},
        },
      })

      if (signInOut?.isSignedIn) {
        setAuthUser(await Auth.fetchUserAttributes())
      }

      return signInOut
    },
    [],
  )

  const ctxValue = useMemo<AuthContextType>(
    () => ({
      authUser,
      signIn,
      currentUser,
    }),
    [authUser, signIn, currentUser],
  )

  return (
    <AuthContext.Provider value={ctxValue}>{children}</AuthContext.Provider>
  )
}
