"use client"

import { createContext, useContext, useEffect, useMemo, useState } from "react"
import { customSessionClient } from "better-auth/client/plugins"
import { createAuthClient } from "better-auth/react"
import type { AppAuth } from "@/lib/auth"
import { useMutation } from "convex/react"

import { api } from "@/convex/_generated/api"
import { DEFAULT_TENANT_ID } from "@/lib/constants"
import { isAdmin, isStaff } from "@/lib/authz"

export type AppSession = {
  user: {
    id: string
    name?: string | null
    email: string
    role: string
    tenantId: string | null
    avatarUrl: string | null
  }
  session: {
    id: string
    expiresAt: number
  }
}

const authClient = createAuthClient({
  plugins: [customSessionClient<AppAuth>()],
  fetchOptions: {
    credentials: "include",
  },
})

type AuthContextValue = {
  session: AppSession | null
  isLoading: boolean
  convexUserId: string | null
  role: string | null
  isAdmin: boolean
  isStaff: boolean
  isCustomer: boolean
}

const AuthContext = createContext<AuthContextValue>({
  session: null,
  isLoading: true,
  convexUserId: null,
  role: null,
  isAdmin: false,
  isStaff: false,
  isCustomer: false,
})

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

export const { signIn, signOut, useSession } = authClient

export function AuthProvider({ children }: { children: React.ReactNode }) {
  const { data: session, isPending } = useSession()
  const ensureUser = useMutation(api.users.ensureUser)
  const [convexUserId, setConvexUserId] = useState<string | null>(null)

  useEffect(() => {
    if (!session?.user) {
      setConvexUserId(null)
    }
  }, [session?.user])

  useEffect(() => {
    if (!session?.user || convexUserId) return

    const controller = new AbortController()

    ;(async () => {
      try {
        const ensured = await ensureUser({
          tenantId: session.user.tenantId ?? DEFAULT_TENANT_ID,
          name: session.user.name ?? session.user.email,
          email: session.user.email,
          avatarUrl: session.user.avatarUrl ?? undefined,
          role: session.user.role.toUpperCase(),
        })
        if (!controller.signal.aborted) {
          setConvexUserId(ensured?._id ?? null)
        }
      } catch (error) {
        if (!controller.signal.aborted) {
          console.error("Failed to sync user with Convex", error)
        }
      }
    })()

    return () => {
      controller.abort()
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [ensureUser, session?.user?.email, session?.user?.tenantId, session?.user?.role, convexUserId])

  const normalizedRole = session?.user?.role ? session.user.role.toLowerCase() : null

  const value = useMemo<AuthContextValue>(
    () => ({
      session: session ?? null,
      isLoading: isPending,
      convexUserId,
      role: normalizedRole,
      isAdmin: isAdmin(normalizedRole),
      isStaff: isStaff(normalizedRole),
      isCustomer: false,
    }),
    [session, isPending, convexUserId, normalizedRole]
  )

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