import { createContext, useContext, useEffect, useRef, useState, useCallback } from 'react'
import axios from 'axios'
import { registerAuthBridge } from './token-bridge'

const AuthContext = createContext(null)

const BASE_URL = import.meta.env.VITE_API_BASE_URL

// Raw axios (not apiClient) for auth calls — avoids the interceptor
// triggering a refresh loop while we're the one doing the refresh.
const authAxios = axios.create({
  baseURL: BASE_URL,
  withCredentials: true,
})

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

  // Keep access token in a ref so api-client (via bridge) always reads the
  // latest value synchronously — React state updates are async.
  const accessTokenRef = useRef(null)

  const clearSession = useCallback(() => {
    accessTokenRef.current = null
    setUser(null)
  }, [])

  const applyTokens = useCallback((accessToken, profile) => {
    accessTokenRef.current = accessToken
    setUser(profile)
  }, [])

  const login = useCallback(async (email, password) => {
    const res = await authAxios.post('/internal/auth/login', { email, password })
    const { access_token, profile } = res.data.data
    applyTokens(access_token, profile)
  }, [applyTokens])

  const refresh = useCallback(async () => {
    try {
      const res = await authAxios.post('/internal/auth/refresh')
      const { access_token, profile } = res.data.data
      applyTokens(access_token, profile)
      return access_token
    } catch {
      clearSession()
      return null
    }
  }, [applyTokens, clearSession])

  const logout = useCallback(async () => {
    try {
      await authAxios.post('/internal/auth/logout', null, {
        headers: accessTokenRef.current ? { Authorization: `Bearer ${accessTokenRef.current}` } : {},
      })
    } catch {
      // server-side session may already be gone; always clear locally
    }
    clearSession()
  }, [clearSession])

  // Wire the bridge once — api-client imports token-bridge directly and
  // reads through these closures, so identity doesn't matter as long as
  // they read fresh state.
  useEffect(() => {
    registerAuthBridge({
      getAccessToken: () => accessTokenRef.current,
      runRefresh: refresh,
      onUnauthenticated: clearSession,
    })
  }, [refresh, clearSession])

  // Bootstrap: try to refresh using the httpOnly cookie. If none / expired,
  // we stay unauthenticated and the router sends us to /login.
  useEffect(() => {
    let cancelled = false
    ;(async () => {
      await refresh()
      if (!cancelled) setLoading(false)
    })()
    return () => { cancelled = true }
    // refresh is stable enough — we only want this to run on mount.
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

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

export const useAuth = () => useContext(AuthContext)
