'use client'

import React from 'react'
import { motion, useReducedMotion } from 'framer-motion'
import './Button.css'

type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'danger'
type ButtonSize = 'sm' | 'md' | 'lg'

// Omit HTML drag events that clash with Framer Motion's onDrag signature
type NoDrag<T> = Omit<T, 'onDrag' | 'onDragStart' | 'onDragEnd' | 'onDragOver' | 'onDragEnter' | 'onDragLeave' | 'onDrop'>

interface ButtonBaseProps {
  variant?: ButtonVariant
  size?: ButtonSize
  loading?: boolean
  className?: string
  children: React.ReactNode
}

type ButtonAsButton = ButtonBaseProps &
  NoDrag<Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, keyof ButtonBaseProps>> & {
    href?: undefined
  }

type ButtonAsAnchor = ButtonBaseProps &
  NoDrag<Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, keyof ButtonBaseProps>> & {
    href: string
  }

export type ButtonProps = ButtonAsButton | ButtonAsAnchor

export function Button(props: ButtonProps) {
  const {
    variant = 'primary',
    size = 'md',
    loading = false,
    className = '',
    children,
    href,
    ...rest
  } = props

  const shouldReduceMotion = useReducedMotion()
  const disabled = href === undefined ? (rest as ButtonAsButton).disabled : false
  const isDisabled = disabled || loading

  const motionProps = isDisabled || shouldReduceMotion
    ? {}
    : {
        whileHover: { scale: 1.02 },
        whileTap: { scale: 0.97 },
        transition: { duration: 0.14, ease: [0.22, 0.61, 0.36, 1] as const },
      }

  const sharedAttrs = {
    'data-variant': variant,
    'data-size': size,
    className: `ov-btn${className ? ` ${className}` : ''}`,
  }

  const content = (
    <>
      {loading && <span className="ov-btn-spinner" data-testid="button-spinner" aria-hidden="true" />}
      {children}
    </>
  )

  if (href !== undefined) {
    const { ...anchorRest } = rest as NoDrag<Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, keyof ButtonBaseProps>>
    return (
      <motion.a href={href} {...sharedAttrs} {...(anchorRest as object)} {...motionProps}>
        {content}
      </motion.a>
    )
  }

  const { disabled: _ignored, ...buttonRest } = rest as NoDrag<Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, keyof ButtonBaseProps>> & { disabled?: boolean }
  return (
    <motion.button disabled={isDisabled} {...sharedAttrs} {...(buttonRest as object)} {...motionProps}>
      {content}
    </motion.button>
  )
}
