import {
  CircleNotchIcon,
  DownloadSimpleIcon,
  IconProps,
} from '@phosphor-icons/react'
import classNames from 'classnames'
import React, { useCallback, useState } from 'react'

import { triggerDownload } from './triggerDownload'
import { VIEWER_ACTION_CLASS } from './viewerChromeClasses'

export type DownloadActionVariant =
  /** Solid pill button used inside compact / file rows. */
  | 'pill'
  /**
   * Compact round icon button sized for the trailing slot of a
   * `CompactDocumentRow` (PDF / File rows). Adopts the row's tone so
   * it sits inline next to the filename without competing with it.
   */
  | 'inline'
  /**
   * Round icon button sized to match the close action in the
   * `ViewerShell` chrome — used by `ImageViewer` for in-viewer
   * downloads. Shares `VIEWER_ACTION_CLASS` with the close button.
   */
  | 'viewer'

export interface DownloadActionProps {
  url: string
  filename?: string
  variant?: DownloadActionVariant
  /**
   * Override the visible label on `pill` variants. Defaults to
   * `'Download'`. On `inline` / `viewer` variants the label is
   * hidden visually and surfaced as the button's `aria-label`.
   */
  label?: string
  /** Hide the label, keeping just the icon. Defaults to `true` for non-pill variants. */
  iconOnly?: boolean
  /** Tone of the surface. Used by the `pill` variant. */
  tone?: 'dark' | 'light'
  /**
   * Triggered after the download starts so consumers can fire analytics
   * or close a viewer. Errors during download don't suppress the call.
   */
  onTriggered?: () => void
}

const DownloadAction: React.FC<DownloadActionProps> = ({
  url,
  filename,
  variant = 'pill',
  label = 'Download',
  iconOnly,
  tone = 'dark',
  onTriggered,
}) => {
  const [busy, setBusy] = useState(false)

  const handleClick = useCallback(
    (e: React.MouseEvent) => {
      e.stopPropagation()
      if (busy) return
      setBusy(true)
      triggerDownload(url, filename)
        .catch(() => {
          /* swallowed — fallback path inside `triggerDownload` */
        })
        .finally(() => {
          setBusy(false)
          onTriggered?.()
        })
    },
    [busy, url, filename, onTriggered]
  )

  const showIconOnly = iconOnly ?? variant !== 'pill'

  const iconClass = classNames(
    variant === 'pill' ? 'size-4' : 'size-5',
    'shrink-0'
  )
  const iconProps: IconProps = { className: iconClass, weight: 'bold' }

  if (variant === 'inline') {
    // Sized to match the existing trailing slot used by `DismissButton`
    // and the decorative download span in `FileAttachment`. Tone keys
    // off the surrounding `Bubble` variant so a sender (dark) bubble
    // gets a lighter icon and a receiver (light) bubble gets a darker
    // one — same approach `CompactDocumentRow` already uses for the
    // type icon.
    const inlineToneClasses: Record<'dark' | 'light', string> = {
      dark: 'text-white/70 hover:bg-white/[0.08] hover:text-white',
      light: 'text-black/70 hover:bg-black/[0.08] hover:text-black',
    }
    return (
      <button
        type="button"
        onClick={handleClick}
        disabled={busy}
        aria-label={label}
        className={classNames(
          'flex size-8 shrink-0 items-center justify-center rounded-full transition-colors disabled:opacity-70',
          inlineToneClasses[tone]
        )}
      >
        {busy ? (
          <CircleNotchIcon
            className="size-4 animate-spin"
            weight="bold"
            aria-hidden
          />
        ) : (
          <DownloadSimpleIcon
            className="size-5 shrink-0"
            weight="bold"
            aria-hidden
          />
        )}
      </button>
    )
  }

  if (variant === 'viewer') {
    // Sits next to the close action inside `ViewerShell`'s top-right chrome
    // and shares its circular-button styling via `VIEWER_ACTION_CLASS`.
    return (
      <button
        type="button"
        onClick={handleClick}
        disabled={busy}
        aria-label={label}
        className={VIEWER_ACTION_CLASS}
      >
        {busy ? (
          <CircleNotchIcon size={20} weight="bold" aria-hidden />
        ) : (
          <DownloadSimpleIcon size={20} weight="bold" aria-hidden />
        )}
      </button>
    )
  }

  // pill — only remaining variant
  return (
    <button
      type="button"
      onClick={handleClick}
      disabled={busy}
      aria-label={showIconOnly ? label : undefined}
      className={classNames(
        'mt-3 inline-flex h-10 w-full items-center justify-center gap-2 rounded-full px-4 text-sm font-medium leading-none transition-colors disabled:opacity-70',
        tone === 'dark'
          ? 'bg-[#121110] text-white hover:bg-[#2a2928]'
          : 'bg-white text-[#121110] hover:bg-white/90'
      )}
    >
      {busy ? (
        <CircleNotchIcon
          className="size-4 animate-spin"
          weight="bold"
          aria-hidden
        />
      ) : (
        <DownloadSimpleIcon {...iconProps} aria-hidden />
      )}
      {showIconOnly ? null : label}
    </button>
  )
}

export default DownloadAction
