"use client"

import { useCallback, useEffect, useMemo, useRef, useState } from "react"
import { Loader2 } from "lucide-react"
import { AuthCard } from "@/components/auth/auth-card"
import { AuthConnectButton } from "@/components/auth/auth-connect-button"
import { FlowChallengeForm } from "@/components/auth/flow-challenge-form"
import {
  AUTH_FLOW_SLUGS,
  isAuthenticationFlow,
  type AuthFlowSlug,
} from "@/lib/auth/auth-flow-slugs"
import {
  completeAuthFlow,
  flowComponent,
  flowRedirectUrl,
  flowTitle,
  flowValidationErrors,
  isRecoveryEmailSent,
  respondAuthFlow,
  startAuthFlow,
  type FlowChallenge,
} from "@/lib/auth/flow-api"

type AuthFlowPageProps = {
  slug: AuthFlowSlug
  flowQuery?: string
  defaultTitle: string
  defaultDescription: string
  successTitle: string
  successDescription: string
  successActionLabel: string
  successHref: string
  /** Full document navigation required (OIDC login routes). */
  successExternal?: boolean
  /** After embedded auth flow, bridge to OIDC session via BFF /flows/complete. */
  bridgeAuthentication?: boolean
  returnTo?: string
  initialError?: string | null
  footer: React.ReactNode
  onSuccess?: () => void
}

function decodeAuthError(value: string | null | undefined): string | null {
  if (!value) return null
  try {
    return decodeURIComponent(value)
  } catch {
    return value
  }
}

export function AuthFlowPage({
  slug,
  flowQuery,
  defaultTitle,
  defaultDescription,
  successTitle,
  successDescription,
  successActionLabel,
  successHref,
  successExternal = false,
  bridgeAuthentication = false,
  returnTo = "/mail/inbox",
  initialError = null,
  footer,
  onSuccess,
}: AuthFlowPageProps) {
  const [sessionId, setSessionId] = useState<string | null>(null)
  const [challenge, setChallenge] = useState<FlowChallenge | null>(null)
  const [loading, setLoading] = useState(true)
  const [submitting, setSubmitting] = useState(false)
  const [bridging, setBridging] = useState(false)
  const [flowError, setFlowError] = useState<string | null>(null)
  const [done, setDone] = useState(false)
  const [denied, setDenied] = useState(false)
  const bridgedRef = useRef(false)
  const redirectError = decodeAuthError(initialError)

  const finishAuthentication = useCallback(async () => {
    if (!bridgeAuthentication || !isAuthenticationFlow(slug) || bridgedRef.current) {
      onSuccess?.()
      return
    }
    bridgedRef.current = true
    setBridging(true)
    setFlowError(null)
    try {
      const { redirectUrl } = await completeAuthFlow(returnTo)
      window.location.href = redirectUrl
    } catch (err) {
      bridgedRef.current = false
      setBridging(false)
      setFlowError(
        err instanceof Error ? err.message : "Impossible de finaliser la connexion"
      )
    }
  }, [bridgeAuthentication, onSuccess, returnTo, slug])

  const redirectToOidcLogin = useCallback(() => {
    const params = new URLSearchParams({ returnTo })
    window.location.assign(`/api/auth/login?${params.toString()}`)
  }, [returnTo])

  const bootstrap = useCallback(async () => {
    setLoading(true)
    try {
      const step = await startAuthFlow(slug, flowQuery)
      setSessionId(step.sessionId)
      setChallenge(step.challenge)
      setDone(step.done)
      setDenied(step.denied)
      if (step.done && !step.denied) {
        if (bridgeAuthentication) {
          // Start returned immediate redirect — no flow session cookie for /complete.
          redirectToOidcLogin()
          return
        }
        onSuccess?.()
      }
    } catch (err) {
      setFlowError(
        err instanceof Error ? err.message : "Impossible de démarrer le parcours"
      )
    } finally {
      setLoading(false)
    }
  }, [bridgeAuthentication, flowQuery, onSuccess, redirectToOidcLogin, slug])

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

  const handleSubmit = useCallback(
    async (payload: Record<string, unknown>) => {
      if (!sessionId) return
      setSubmitting(true)
      setFlowError(null)
      try {
        const step = await respondAuthFlow(slug, payload, flowQuery)
        setSessionId(step.sessionId)
        setChallenge(step.challenge)
        setDone(step.done)
        setDenied(step.denied)
        if (step.done && !step.denied) {
          await finishAuthentication()
        }
      } catch (err) {
        setFlowError(err instanceof Error ? err.message : "Échec de l'étape")
      } finally {
        setSubmitting(false)
      }
    },
    [finishAuthentication, flowQuery, sessionId, slug]
  )

  const validationErrors = useMemo(() => flowValidationErrors(challenge), [challenge])
  const formError = flowError ?? redirectError ?? validationErrors._form ?? null

  const title = useMemo(() => {
    if ((done && !denied) || isRecoveryEmailSent(slug, challenge)) return successTitle
    if (denied) return "Accès refusé"
    return flowTitle(challenge) || defaultTitle
  }, [challenge, defaultTitle, denied, done, slug, successTitle])

  const description = useMemo(() => {
    if ((done && !denied) || isRecoveryEmailSent(slug, challenge)) return successDescription
    if (denied) {
      return "Ce parcours a été refusé. Vérifiez vos informations ou contactez le support."
    }
    return defaultDescription
  }, [challenge, defaultDescription, denied, done, slug, successDescription])

  const component = flowComponent(challenge)
  const redirectUrl = flowRedirectUrl(challenge)
  const recoveryEmailSent = isRecoveryEmailSent(slug, challenge)
  const showSuccess =
    (done && !denied && !bridgeAuthentication) || recoveryEmailSent

  return (
    <AuthCard title={title} description={description} error={formError} footer={footer}>
      {loading || bridging ? (
        <div className="flex justify-center py-8">
          <Loader2 className="size-6 animate-spin text-muted-foreground" aria-hidden />
          <span className="sr-only">{bridging ? "Finalisation…" : "Chargement…"}</span>
        </div>
      ) : showSuccess ? (
        <div className="flex flex-col items-center gap-4">
          {redirectUrl ? (
            <p className="text-center text-sm text-muted-foreground">
              Redirection en cours…
            </p>
          ) : null}
          {successExternal ? (
            <AuthConnectButton href={successHref}>
              {successActionLabel}
            </AuthConnectButton>
          ) : (
            <AuthConnectButton as="link" href={successHref}>
              {successActionLabel}
            </AuthConnectButton>
          )}
        </div>
      ) : (
        <FlowChallengeForm
          challenge={challenge}
          component={component}
          submitting={submitting}
          fieldErrors={validationErrors}
          flowSlug={slug}
          onSubmit={handleSubmit}
        />
      )}
    </AuthCard>
  )
}

export { AUTH_FLOW_SLUGS }
