import React from 'react'

import Bubble from '../_shared/Bubble'
import CompactDocumentRow from '../_shared/CompactDocumentRow'
import DismissButton from '../_shared/DismissButton'
import DownloadAction from '../_shared/DownloadAction'
import { filenameFromUrl } from '../_shared/fileMeta'
import PdfViewer, { type PdfViewerItem } from '../_shared/PdfViewer'
import { useViewer } from '../_shared/useViewer'
import {
  bubbleVariantForState,
  type BubbleVariant,
  type ComposerExtras,
  type MessageAttachmentBaseProps,
  type MessageAttachmentState,
  type PdfItem,
} from '../types'

export interface PdfAttachmentSharedProps extends MessageAttachmentBaseProps {
  /** Single PDF — convenience for the most common case. */
  src?: string
  /** Filename — drives the row title + the meta line + the viewer dialog's accessible name. */
  filename?: string
  /** File size in bytes — formatted into the `EXT · SIZE` meta line. */
  fileSize?: number
  /**
   * Override displayed title (defaults to `filename`). Useful when a
   * sender re-titles a generated PDF before sending.
   */
  title?: string
  /**
   * Stacked PDFs. Takes precedence over `src` when set. Each item
   * renders as its own row inside the bubble; clicking a row opens
   * that PDF in the viewer. Sent + Received only — the composer
   * surface accepts a single attachment at a time.
   */
  items?: PdfItem[]
  /**
   * Forwarded to the viewer trigger. When omitted the click still
   * opens the built-in `PdfViewer`. Supply this to fire analytics, or
   * return `false` to intercept the open (e.g. swap to a route-based
   * viewer / confirmation modal). Any other return value (including
   * `void`/`undefined`) lets the built-in viewer open. For stacked
   * attachments the `index` argument identifies the row.
   */
  onClick?: (index: number) => boolean | void
}

const resolveItems = ({
  src,
  filename,
  fileSize,
  title,
  items,
}: {
  src?: string
  filename?: string
  fileSize?: number
  title?: string
  items?: PdfItem[]
}): PdfItem[] => {
  if (items && items.length > 0) return items
  if (src) return [{ src, filename, fileSize, title }]
  return []
}

interface PdfRowButtonProps {
  variant: BubbleVariant
  item: PdfItem
  index: number
  onActivate: (index: number) => void
  trailingAction?: React.ReactNode
}

/**
 * Single tappable PDF row — used both for the lone PDF case and for
 * each child of a stacked attachment. The icon + filename area opens
 * the viewer; the trailing slot hosts a separate, sibling button
 * (download or dismiss) so each affordance owns its own click target.
 */
const PdfRowButton: React.FC<PdfRowButtonProps> = ({
  variant,
  item,
  index,
  onActivate,
  trailingAction,
}) => {
  const resolvedFilename = item.filename ?? filenameFromUrl(item.src)
  return (
    <CompactDocumentRow
      variant={variant}
      filename={resolvedFilename}
      title={item.title}
      mimeType="application/pdf"
      fileSize={item.fileSize}
      onActivate={() => onActivate(index)}
      activateLabel={`Open ${resolvedFilename}`}
      trailingAction={trailingAction}
    />
  )
}

interface InternalPdfRowProps extends PdfAttachmentSharedProps {
  state: MessageAttachmentState
  onDismiss?: () => void
}

const PdfAttachmentRow: React.FC<InternalPdfRowProps> = ({
  state,
  src,
  filename,
  fileSize,
  title,
  items,
  text,
  groupPosition,
  onClick,
  onDismiss,
}) => {
  const variant = bubbleVariantForState(state)
  const resolvedItems = resolveItems({ src, filename, fileSize, title, items })
  const { viewerOpen, viewerIndex, handleActivate, closeViewer } =
    useViewer(onClick)
  const showDismiss = state === 'composer' && !!onDismiss

  if (resolvedItems.length === 0) {
    return null
  }

  // Project the bubble's `PdfItem`s onto the viewer's carousel-aware
  // shape. The viewer clamps its own active index defensively, so we
  // don't need to second-guess `viewerIndex` here.
  const viewerItems: PdfViewerItem[] = resolvedItems.map((item) => ({
    src: item.src,
    filename: item.filename ?? filenameFromUrl(item.src),
  }))

  return (
    <Bubble
      variant={variant}
      text={text}
      groupPosition={groupPosition}
      data-testid="pdf-attachment"
    >
      {/* Stacked rows get a small vertical gap so each PDF reads as
          a discrete attachment rather than one merged blob. Single
          row falls through to a no-op `gap-0`. */}
      <div className="flex flex-col gap-2">
        {resolvedItems.map((item, index) => {
          const itemFilename = item.filename ?? filenameFromUrl(item.src)
          // Composer only supports a single attachment so the dismiss
          // control sits on the only row. Sent / Received rows expose
          // a download icon button so the user can grab the PDF
          // without opening the viewer first — the viewer dialog is
          // intentionally just the document + a close button, so this
          // sibling action is the only one-click download surface.
          const trailingAction =
            showDismiss && index === 0 ? (
              <DismissButton onClick={onDismiss!} variant="inline" />
            ) : state === 'composer' ? undefined : (
              <DownloadAction
                url={item.src}
                filename={itemFilename}
                variant="inline"
                label={`Download ${itemFilename}`}
                tone={variant}
              />
            )
          return (
            <PdfRowButton
              key={`${item.src}-${index}`}
              variant={variant}
              item={item}
              index={index}
              onActivate={handleActivate}
              trailingAction={trailingAction}
            />
          )
        })}
      </div>

      <PdfViewer
        open={viewerOpen}
        items={viewerItems}
        initialIndex={viewerIndex}
        onClose={closeViewer}
      />
    </Bubble>
  )
}

/**
 * Composer-only props. Single PDF (`src`) only — the composer surface
 * accepts a single attachment at a time, so `items` is not supported.
 * Captions (`text`) and `groupPosition` are also dropped: the composer
 * renders a standalone draft, not part of a same-author run, and
 * captions live in the message-input textarea, not inside the draft
 * attachment preview.
 */
export interface PdfComposerProps extends ComposerExtras {
  src?: string
  filename?: string
  fileSize?: number
  title?: string
  onClick?: (index: number) => boolean | void
}
export type PdfSentProps = PdfAttachmentSharedProps
export type PdfReceivedProps = PdfAttachmentSharedProps

const PdfComposer: React.FC<PdfComposerProps> = (props) => (
  <PdfAttachmentRow {...props} state="composer" />
)
const PdfSent: React.FC<PdfSentProps> = (props) => (
  <PdfAttachmentRow {...props} state="sent" />
)
const PdfReceived: React.FC<PdfReceivedProps> = (props) => (
  <PdfAttachmentRow {...props} state="received" />
)

const PdfAttachment = {
  Composer: PdfComposer,
  Sent: PdfSent,
  Received: PdfReceived,
}

export default PdfAttachment
