import * as React from 'react'
import {useState, useCallback} from 'react'

import {Product} from '@shopify/shop-minis-platform'
import {CheckIcon} from 'lucide-react'
import {motion, AnimatePresence} from 'motion/react'

import {useErrorToast, useShopNavigation} from '../../hooks'
import {useShopCartActions} from '../../internal/useShopCartActions'
import {cn} from '../../lib/utils'
import {Button} from '../atoms/button'

/**
 * Adds products to Shop's cart with checkmark animation feedback. Users can continue shopping and add more items before checkout. Use this for browsing experiences where customers might want multiple products. For immediate single-product purchases, use `BuyNowButton` instead.
 * @publicDocs
 */
export interface AddToCartButtonProps {
  /** Whether the button is disabled */
  disabled?: boolean
  /** CSS class name */
  className?: string
  /** Button size variant */
  size?: 'default' | 'sm' | 'lg'
  /** The discount codes to apply to the cart */
  discountCodes?: string[]
  /** The GID of the product variant. E.g. `gid://shopify/ProductVariant/456` */
  productVariantId: string
  /** The product to add to the cart */
  product?: Product
}

export function AddToCartButton({
  disabled = false,
  className,
  size = 'default',
  productVariantId,
  discountCodes,
  product,
}: AddToCartButtonProps) {
  const {addToCart} = useShopCartActions()
  const {navigateToProduct} = useShopNavigation()
  const [isAdded, setIsAdded] = useState(false)
  const timeoutRef = React.useRef<number | undefined>(undefined)
  const {id, referral, variants, selectedVariant} = product ?? {}

  // Look up the matching variant from `variants` first (productLists/savedProducts
  // path); otherwise fall back to `selectedVariant` (useProduct/useProducts marketplace path).
  const matchingVariant =
    variants?.find(variant => variant.id === productVariantId) ??
    (selectedVariant?.id === productVariantId ? selectedVariant : undefined)
  const variantImageUrl = matchingVariant?.image?.url
  const isSoldOut = matchingVariant?.availableForSale === false
  // Referral products only navigate to the PDP — never gate them on stock so a
  // sold-out selected variant doesn't strand the user without a way to switch.
  const isDisabled = disabled || (!referral && isSoldOut)

  const {showErrorToast} = useErrorToast()

  const handleClick = useCallback(async () => {
    if (isDisabled) return

    if (id && referral) {
      navigateToProduct({
        productId: id,
      })

      return
    }

    if (isAdded) return

    try {
      if (id && productVariantId) {
        addToCart({
          productId: id,
          productVariantId,
          quantity: 1,
          discountCodes,
          variantImageUrl,
        })
          .then(() => {})
          .catch(() => {
            showErrorToast({message: 'Failed to add to cart'})
          })
      }

      // Show success state
      setIsAdded(true)

      // Clear any existing timeout
      if (timeoutRef.current) {
        clearTimeout(timeoutRef.current)
      }

      // Reset to initial state after delay
      timeoutRef.current = window.setTimeout(() => {
        setIsAdded(false)
      }, 2000)
    } catch (error) {
      // Handle error - reset to initial state
      setIsAdded(false)
      console.error('Failed to add to cart:', error)
    }
  }, [
    isDisabled,
    id,
    referral,
    isAdded,
    navigateToProduct,
    productVariantId,
    addToCart,
    discountCodes,
    variantImageUrl,
    showErrorToast,
  ])

  // Cleanup timeout on unmount
  React.useEffect(() => {
    return () => {
      if (timeoutRef.current) {
        clearTimeout(timeoutRef.current)
      }
    }
  }, [])

  const getButtonText = () => {
    if (referral) return 'View product'
    if (isSoldOut) return 'Sold out'
    if (isAdded) return 'Added to cart'
    return 'Add to cart'
  }
  const buttonText = getButtonText()

  return (
    <Button
      onClick={handleClick}
      disabled={isDisabled}
      className={cn(
        'relative overflow-hidden transition-all duration-300',
        className
      )}
      size={size}
    >
      <div className="relative flex items-center justify-center">
        <AnimatePresence>
          {isAdded && !isSoldOut && (
            <motion.div
              initial={{scale: 0, rotate: -180}}
              animate={{scale: 1, rotate: 0}}
              exit={{scale: 0, rotate: 180}}
              transition={{
                duration: 0.4,
                ease: [0.175, 0.885, 0.32, 1.275], // bounce effect
              }}
              className="absolute left-2"
              style={{x: -8}}
            >
              <CheckIcon className="size-4" />
            </motion.div>
          )}
        </AnimatePresence>
        <span
          className={cn(
            isAdded && !isSoldOut && 'pl-5',
            'transition-all duration-300'
          )}
        >
          {buttonText}
        </span>
      </div>
    </Button>
  )
}
