'use client'

import {
  createContext,
  useContext,
  useEffect,
  useState,
  useCallback,
  createElement,
  type ReactNode,
} from 'react'
import {
  createWebAuthClient,
  createWebRelayApiClient,
  getStoredToken,
  clearStoredToken,
  type WebAuthClient,
  type WebRelayApiClient,
} from '@bowong/auth/client'

const RELAY_URL = process.env.NEXT_PUBLIC_RELAY_URL ?? 'http://localhost:8787'

const authClient = createWebAuthClient(RELAY_URL)
const relayApiClient = createWebRelayApiClient(RELAY_URL)

interface AuthUser {
  id: string
  name: string | null
  email: string
}

interface AuthContextValue {
  user: AuthUser | null
  loading: boolean
  token: string | null
  authClient: WebAuthClient
  relayApiClient: WebRelayApiClient
  signOut: () => Promise<void>
  refreshSession: () => Promise<void>
}

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

export function AuthProvider({ children }: { children: ReactNode }) {
  const [user, setUser] = useState<AuthUser | null>(null)
  const [loading, setLoading] = useState(true)
  const [token, setToken] = useState<string | null>(null)

  const refreshSession = useCallback(async () => {
    try {
      const { data: session } = await authClient.getSession()
      if (session?.user) {
        setUser({
          id: session.user.id,
          name: session.user.name,
          email: session.user.email,
        })
        setToken(getStoredToken())
      } else {
        setUser(null)
        setToken(null)
      }
    } catch {
      setUser(null)
      setToken(null)
    } finally {
      setLoading(false)
    }
  }, [])

  useEffect(() => {
    void refreshSession()
  }, [refreshSession])

  const signOut = useCallback(async () => {
    await authClient.signOut()
    clearStoredToken()
    setUser(null)
    setToken(null)
  }, [])

  return createElement(
    AuthContext.Provider,
    {
      value: { user, loading, token, authClient, relayApiClient, signOut, refreshSession },
    },
    children,
  )
}

export function useAuth(): AuthContextValue {
  const ctx = useContext(AuthContext)
  if (!ctx) {
    throw new Error('useAuth must be used within an AuthProvider')
  }
  return ctx
}
