import { createContext, useContext, useEffect, useState, type ReactNode } from 'react'
import { api, getToken, setToken, type AuthUser, type MeshStatus } from './api'

type AuthStatus = 'loading' | 'needs-setup' | 'enrolling' | 'logged-out' | 'needs-mesh' | 'logged-in'

interface AuthContextValue {
  status: AuthStatus
  user: AuthUser | null
  meshStatus: MeshStatus | null
  login: (username: string, password: string) => Promise<void>
  completeSetup: (username: string, password: string) => Promise<void>
  finishEnrollment: () => Promise<void>
  refreshMeshStatus: () => Promise<void>
  logout: () => void
  setUser: (user: AuthUser) => void
}

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

export function AuthProvider({ children }: { children: ReactNode }) {
  const [status, setStatus] = useState<AuthStatus>('loading')
  const [user, setUser] = useState<AuthUser | null>(null)
  const [meshStatus, setMeshStatus] = useState<MeshStatus | null>(null)

  async function refresh() {
    if (getToken()) {
      try {
        const { user } = await api.me()
        setUser(user)
        const mesh = await api.getMeshStatus().catch(() => null)
        setMeshStatus(mesh)
        // Members are let in with a "setup in progress" notice instead of being gated —
        // only an admin can actually fix mesh config, so only admins see the full gate.
        const gateBlocks = !!mesh && mesh.required && !mesh.verified && !mesh.overridden
        setStatus(gateBlocks && user.role === 'admin' ? 'needs-mesh' : 'logged-in')
        return
      } catch {
        setToken(null)
      }
    }
    const { needsSetup } = await api.getSetupStatus()
    setStatus(needsSetup ? 'needs-setup' : 'logged-out')
  }

  async function refreshMeshStatus() {
    await refresh()
  }

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

  async function login(username: string, password: string) {
    const { token } = await api.login(username, password)
    setToken(token)
    await refresh()
  }

  async function completeSetup(username: string, password: string) {
    const { token } = await api.setup(username, password)
    setToken(token)
    const { user } = await api.me()
    setUser(user)
    setStatus('enrolling')
  }

  async function finishEnrollment() {
    await refresh()
  }

  function logout() {
    // Best-effort server-side session revocation; clear client state regardless.
    api.logout().catch(() => {})
    setToken(null)
    setUser(null)
    setMeshStatus(null)
    setStatus('logged-out')
  }

  return (
    <AuthContext.Provider
      value={{ status, user, meshStatus, login, completeSetup, finishEnrollment, refreshMeshStatus, logout, setUser }}
    >
      {children}
    </AuthContext.Provider>
  )
}

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