'use client'

import React from 'react'
import { SvgCheck, SvgCopy } from '@chainlink/blocks-icons'
import { useClipboardCopy } from '../../hooks/useClipboardCopy'
import { cn } from '../../utils/cn'
import {
  Popover,
  PopoverArrow,
  PopoverContent,
  PopoverTrigger,
} from '../Popover'

// ============================================================================
// Copy Context
// ============================================================================

type CopyContextValue = {
  /**
   * The text to be copied to the clipboard.
   */
  text: string
  /**
   * Whether the text was recently copied.
   */
  isCopied: boolean
  /**
   * Function to copy the text to the clipboard.
   */
  copy: () => void
}

const CopyContext = React.createContext<CopyContextValue | null>(null)

/**
 * Hook to access the Copy context. Must be used within a CopyRoot.
 *
 * @example
 * ```tsx
 * const { isCopied, copy, text } = useCopyContext()
 * ```
 */
export const useCopyContext = () => {
  const context = React.useContext(CopyContext)
  if (!context) {
    throw new Error('useCopyContext must be used within a CopyRoot')
  }
  return context
}

/**
 * Hook to get copy functionality. Can be used standalone with text prop,
 * or within a CopyRoot to use context.
 *
 * @param text - Optional text to copy. If provided, uses standalone mode.
 *               If omitted, reads from CopyRoot context.
 *
 * @example
 * ```tsx
 * // Standalone usage
 * const { isCopied, copy } = useCopy('Hello')
 *
 * // Context usage (within CopyRoot)
 * const { isCopied, copy, text } = useCopy()
 * ```
 */
export const useCopy = (text?: string) => {
  const context = React.useContext(CopyContext)
  const localClipboard = useClipboardCopy()

  const isStandalone = text !== undefined

  const resolvedText = isStandalone ? text : context?.text
  const isCopied = isStandalone
    ? localClipboard.isCopied
    : (context?.isCopied ?? false)

  const copy = React.useCallback(() => {
    if (isStandalone && resolvedText) {
      void localClipboard.copy(resolvedText)
    } else {
      context?.copy()
    }
  }, [isStandalone, resolvedText, localClipboard, context])

  return { text: resolvedText, isCopied, copy }
}

// ============================================================================
// CopyRoot
// ============================================================================

export type CopyRootProps = {
  /**
   * The text to be copied to the clipboard.
   */
  text: string
  /**
   * The content of the copy component.
   */
  children: React.ReactNode
  /**
   * Additional class names for the root wrapper.
   */
  className?: string
} & Omit<React.HTMLAttributes<HTMLDivElement>, 'children'>

/**
 * Root component that provides copy context and layout styling.
 * Use this primitive to build custom copy components.
 *
 * @example
 * ```tsx
 * <CopyRoot text="0x123456789abcdef">
 *   0x1234...abcd
 *   <CopyTrigger />
 * </CopyRoot>
 * ```
 */
export const CopyRoot = React.forwardRef<HTMLDivElement, CopyRootProps>(
  ({ text, children, className, ...props }, ref) => {
    const { isCopied, copy: copyToClipboard } = useClipboardCopy()

    const copy = React.useCallback(() => {
      void copyToClipboard(text)
    }, [copyToClipboard, text])

    return (
      <CopyContext.Provider value={{ text, isCopied, copy }}>
        <div
          ref={ref}
          className={cn('flex items-center gap-2', className)}
          {...props}
        >
          {children}
        </div>
      </CopyContext.Provider>
    )
  },
)
CopyRoot.displayName = 'CopyRoot'

// ============================================================================
// CopyTrigger
// ============================================================================

export type CopyTriggerProps = {
  /**
   * The text to copy. If provided, CopyTrigger can be used standalone without CopyRoot.
   * If omitted, text will be read from CopyRoot context.
   */
  text?: string
  /**
   * Custom icon to show when not copied.
   */
  defaultIcon?: React.ReactNode
  /**
   * Custom icon to show when copied.
   */
  copiedIcon?: React.ReactNode
  /**
   * Additional class names for the trigger button.
   */
  className?: string
  /**
   * Whether to stop event propagation on click.
   * @default true
   */
  stopPropagation?: boolean
  /**
   * Side of the tooltip popover.
   * @default "top"
   */
  tooltipSide?: 'top' | 'bottom' | 'left' | 'right'
} & Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'onClick' | 'children'>

/**
 * Clickable trigger that copies text and displays status icon with tooltip.
 * Can be used within a CopyRoot (context-based) or standalone with the `text` prop.
 *
 * @example
 * ```tsx
 * // With CopyRoot context
 * <CopyRoot text="Hello">
 *   Hello
 *   <CopyTrigger />
 * </CopyRoot>
 *
 * // Standalone usage
 * <CopyTrigger text="Hello" />
 * ```
 */
export const CopyTrigger = React.forwardRef<
  HTMLButtonElement,
  CopyTriggerProps
>(
  (
    {
      text: textProp,
      defaultIcon,
      copiedIcon,
      className,
      stopPropagation = true,
      tooltipSide = 'top',
      ...props
    },
    ref,
  ) => {
    const { copy, isCopied } = useCopy(textProp)
    const [isHovered, setIsHovered] = React.useState(false)

    const icon = isCopied
      ? (copiedIcon ?? <SvgCheck className="size-4 text-success-foreground" />)
      : (defaultIcon ?? (
          <SvgCopy className="size-4 text-muted-foreground hover:text-foreground" />
        ))

    return (
      <Popover open={isCopied || isHovered}>
        <PopoverTrigger asChild>
          <button
            ref={ref}
            type="button"
            onClick={(e) => {
              if (stopPropagation) {
                e.stopPropagation()
              }
              copy()
            }}
            onMouseEnter={() => setIsHovered(true)}
            onMouseLeave={() => setIsHovered(false)}
            className={cn(
              'inline-flex cursor-pointer items-center justify-center outline-none',
              className,
            )}
            {...props}
          >
            {icon}
          </button>
        </PopoverTrigger>
        <PopoverContent className="outline-none ring-0" side={tooltipSide}>
          {isCopied ? 'Copied!' : 'Copy'}
          <PopoverArrow />
        </PopoverContent>
      </Popover>
    )
  },
)
CopyTrigger.displayName = 'CopyTrigger'
