import { useCallback, useContext, useRef } from 'react'
import { useConfirmPayment } from '@platform-modules/billing-react'
import { CheckoutContext } from './context.js'
import { CheckoutProviderError, isPaymentConfirmError } from './errors.js'

export function useCheckoutConfirm(): {
  confirm: (opts: { returnUrl: string }) => Promise<void>
  status: 'idle' | 'confirming' | 'succeeded' | 'error'
} {
  const ctx = useContext(CheckoutContext)
  if (!ctx) throw new CheckoutProviderError('useCheckoutConfirm')
  // Throws here (billing-react contract) if no PaymentUiContext — the intended guard
  // that this hook runs only inside the host's StripePaymentProvider subtree.
  const { confirm: confirmPayment, status } = useConfirmPayment()
  const { dispatch, state } = ctx
  const confirming = useRef(false)

  const confirm = useCallback(async (opts: { returnUrl: string }): Promise<void> => {
    // Guard: only act in awaiting_payment (§6). A confirm() before submit, after the phase
    // moved on, or while another confirm is in flight is a no-op — never a stray/double charge.
    if (!state.clientSecret || !state.orderId || state.phase !== 'awaiting_payment') return
    if (confirming.current) return
    confirming.current = true
    const orderId = state.orderId
    dispatch({ type: 'CONFIRMING' })
    try {
      // billing-react's ConfirmPaymentOptions = { returnUrl }. The PSP clientSecret is NOT
      // threaded here — it already lives in PaymentUiContext (mounted off the persisted secret).
      const res = await confirmPayment({ returnUrl: opts.returnUrl })
      if (res.kind === 'succeeded') {
        // Money-truth (§9): client success ≠ settlement. Go to settling; the provider poll
        // surfaces 'paid' only off a server-terminal status.
        dispatch({ type: 'SETTLING', orderId })
      } else if (res.kind === 'error') {
        dispatch({ type: 'FAILED', error: isPaymentConfirmError(res.error) ? res.error : null })
      }
      // requires_redirect: leave phase 'confirming' — the browser is navigating away.
    } finally {
      confirming.current = false
    }
  }, [confirmPayment, dispatch, state.clientSecret, state.orderId, state.phase])

  return { confirm, status }
}