import { useCallback, useRef, useState } from 'react'
import type { Vendor } from '@platform-modules/commerce-marketplace'
import { DEFAULT_COMMISSION_BPS } from '@platform-modules/commerce-marketplace'
import type { ApplyAsVendorWire } from './client.js'
import { useMarketplaceContext } from './MarketplaceProvider.js'
import { reviveVendor } from './revive.js'

export type OptimisticVendor = Omit<Vendor, 'id' | 'createdAt' | 'updatedAt' | 'ownerUserId'> & {
  id: null
  ownerUserId: string | null
  createdAt: null
  updatedAt: null
}

export function useApplyAsVendor(): {
  apply: (input: ApplyAsVendorWire) => Promise<Vendor>
  pending: boolean
  optimistic: OptimisticVendor | undefined
  result: Vendor | undefined
  error: Error | undefined
  reset: () => void
} {
  const { client } = useMarketplaceContext('useApplyAsVendor')
  const [optimistic, setOptimistic] = useState<OptimisticVendor | undefined>()
  const [result, setResult] = useState<Vendor | undefined>()
  const [error, setError] = useState<Error | undefined>()
  const [pending, setPending] = useState(false)

  const inflightRef = useRef(0)
  const latestTagRef = useRef(0)

  const apply = useCallback((input: ApplyAsVendorWire): Promise<Vendor> => {
    const tag = ++latestTagRef.current
    inflightRef.current++
    setOptimistic({
      id: null,
      ownerUserId: null,
      name: input.name,
      status: 'pending',
      commissionBps: DEFAULT_COMMISSION_BPS,
      createdAt: null,
      updatedAt: null,
    })
    setPending(inflightRef.current > 0)

    return client
      .applyAsVendor(input)
      .then((wire) => {
        const revived = reviveVendor(wire)
        if (latestTagRef.current === tag) {
          setResult(revived)
          setError(undefined)
          setOptimistic(undefined)
        }
        return revived
      })
      .catch((e: unknown) => {
        if (latestTagRef.current === tag) {
          setError(e instanceof Error ? e : new Error(String(e)))
          setResult(undefined)
          setOptimistic(undefined)
        }
        throw e
      })
      .finally(() => {
        inflightRef.current--
        setPending(inflightRef.current > 0)
      })
  }, [client])

  const reset = useCallback(() => {
    // Orphan any in-flight apply so its later resolve/reject no-ops on visible
    // state (same model as useSubmitReview). The finally still decrements
    // inflightRef — never force the counter, or pending underflows and wedges.
    latestTagRef.current++
    setResult(undefined)
    setError(undefined)
    setOptimistic(undefined)
  }, [])

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