import { useCallback, useRef, useState } from 'react'
import type { ReviewRating } from '@platform-modules/commerce-reviews'
import type { OptimisticReview, SubmitReviewWire } from './client.js'
import { useReviewsClient } from './client.js'
import { type PublicReview, reviveReview } from './revive.js'

export function useSubmitReview(): {
  submit: (input: SubmitReviewWire) => Promise<PublicReview>
  pending: boolean
  optimistic: OptimisticReview | undefined
  result: PublicReview | undefined
  error: unknown
  reset: () => void
} {
  const client = useReviewsClient('useSubmitReview')
  const [inFlight, setInFlight] = useState(0)
  const [optimistic, setOptimistic] = useState<OptimisticReview | undefined>()
  const [result, setResult] = useState<PublicReview | undefined>()
  const [error, setError] = useState<unknown>()

  const pending = inFlight > 0

  const tagRef = useRef(0)
  const latestTagRef = useRef(0)

  const submit = useCallback(async (input: SubmitReviewWire): Promise<PublicReview> => {
    const tag = ++tagRef.current
    latestTagRef.current = tag

    setOptimistic({
      id: null,
      productId: input.productId,
      purchaseId: input.purchaseId,
      userId: undefined,
      vendorId: null,
      rating: input.rating as ReviewRating,
      body: input.body ?? null,
      vendorReply: null,
      status: 'pending',
      createdAt: new Date(),
      updatedAt: new Date(),
    })
    setInFlight((n) => n + 1)

    try {
      const resp = await client.submitReview(input)
      const revived = reviveReview(resp)
      if (latestTagRef.current === tag) {
        setResult(revived)
        setError(undefined)
      }
      return revived
    } catch (e) {
      if (latestTagRef.current === tag) {
        setError(e)
        setOptimistic(undefined)
      }
      throw e
    } finally {
      setInFlight((n) => n - 1)
    }
  }, [client])

  const reset = useCallback(() => {
    // Orphan any in-flight submit so its later resolve/reject no-ops on visible
    // state (it still decrements inFlight in its finally — never force the
    // counter to 0 here, or that decrement underflows to -1 and wedges pending).
    tagRef.current += 1
    latestTagRef.current = tagRef.current
    setOptimistic(undefined)
    setResult(undefined)
    setError(undefined)
  }, [])

  return { submit, pending, optimistic, result, error, reset }
}
