import { createContext, useContext, useEffect, useState, useCallback } from 'react'
import { api } from '../api/client.js'

const AuthContext = createContext(null)

export function AuthProvider({ children }) {
  const [user, setUser] = useState(null)
  const [loading, setLoading] = useState(true)

  const refresh = useCallback(async () => {
    try {
      const data = await api.me()
      setUser(data.user)
    } catch {
      setUser(null)
    } finally {
      setLoading(false)
    }
  }, [])

  useEffect(() => {
    refresh()
  }, [refresh])

  // Step 1. Returns { user } on success, or { totpRequired, challenge } when the
  // account has 2FA on (caller then calls loginTotp). `extra` carries honeypot.
  const login = useCallback(async (username, password, extra) => {
    const data = await api.login(username, password, extra)
    if (data.user) setUser(data.user)
    return data
  }, [])

  // Step 2 for TOTP users: exchange the challenge + code for a real session.
  const loginTotp = useCallback(async (challenge, code) => {
    const data = await api.loginTotp(challenge, code)
    setUser(data.user)
    return data.user
  }, [])

  // Step 2 for SSO logins whose account has 2FA on. The pending challenge lives in
  // an httpOnly cookie, so only the code is sent. Returns { user, returnTo }.
  const ssoLoginTotp = useCallback(async (code) => {
    const data = await api.ssoLoginTotp(code)
    setUser(data.user)
    return data
  }, [])

  const logout = useCallback(async () => {
    try {
      await api.logout()
    } finally {
      setUser(null)
    }
  }, [])

  return (
    <AuthContext.Provider value={{ user, loading, login, loginTotp, ssoLoginTotp, logout, refresh }}>
      {children}
    </AuthContext.Provider>
  )
}

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