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'

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} = product ?? {}

  const variantImageUrl = variants?.find(
    variant => variant.id === productVariantId
  )?.image?.url

  const {showErrorToast} = useErrorToast()

  const handleClick = useCallback(async () => {
    if (disabled) 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)
    }
  }, [
    disabled,
    id,
    referral,
    isAdded,
    navigateToProduct,
    productVariantId,
    addToCart,
    discountCodes,
    variantImageUrl,
    showErrorToast,
  ])

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

  const addToCartText = isAdded ? 'Added to cart' : 'Add to cart'
  const buttonText = referral ? 'View product' : addToCartText

  return (
    <Button
      onClick={handleClick}
      disabled={disabled}
      className={cn(
        'relative overflow-hidden transition-all duration-300',
        className
      )}
      size={size}
    >
      <div className="relative flex items-center justify-center">
        <AnimatePresence>
          {isAdded && (
            <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 && 'pl-5', 'transition-all duration-300')}>
          {buttonText}
        </span>
      </div>
    </Button>
  )
}
