import AudioAttachment, {
  type AudioComposerProps,
  type AudioReceivedProps,
  type AudioSentProps,
} from './Audio'
import FileAttachment, {
  type FileComposerProps,
  type FileReceivedProps,
  type FileSentProps,
} from './File'
import ImageAttachment, {
  type ImageComposerProps,
  type ImageReceivedProps,
  type ImageSentProps,
} from './Image'
import PdfAttachment, {
  type PdfComposerProps,
  type PdfReceivedProps,
  type PdfSentProps,
} from './Pdf'
import VideoAttachment, {
  type VideoComposerProps,
  type VideoReceivedProps,
  type VideoSentProps,
} from './Video'

/**
 * Per-MIME chat attachment cards used inside the messaging stream.
 *
 * Each subnamespace (`Image`, `Video`, `Audio`, `Pdf`, `File`) exposes
 * three states (`Composer`, `Sent`, `Received`) that map to the
 * sender / recipient sides of a chat:
 *
 *   - `Composer` — sender draft state with a dismiss `×` affordance.
 *   - `Sent`     — sender-side state shown after posting.
 *   - `Received` — recipient-side state.
 *
 * Sent / Received variants accept an optional `text` prop that renders
 * inside the same bubble as the attachment — mirroring the mobile chat
 * where a sender can pair a caption with an attachment ('Here is the
 * file', 'Here is the image'). Composer prop types intentionally omit
 * `text` (and `items` / `groupPosition`) so the type system enforces
 * the same contract: captions live in the message-input textarea, not
 * inside the draft attachment preview.
 *
 * Stacked attachments — every type except `Composer` accepts an
 * `items={[…]}` prop on Sent / Received that takes precedence over
 * the singular `src`/`filename`/etc. inputs:
 *
 *   - Image / Video render a 1 / 2 / 3 / 4-tile grid (5+ collapse
 *     into a `+N` overflow tile). Activating any tile opens the
 *     built-in `ImageViewer` / `VideoViewer` at that index; when
 *     `items.length > 1` the lightbox becomes a carousel (prev / next
 *     chrome, ArrowLeft / ArrowRight, current / total counter) so the
 *     user can browse siblings without closing the modal.
 *   - Pdf / Audio / File render their compact rows / players in a
 *     vertical stack with an 8px gap between rows. Each row keeps
 *     its own activation target — Pdf opens the carousel-aware
 *     `PdfViewer` at that index, Audio gets its own native player,
 *     and File downloads the asset for that row.
 *
 * The Composer surface accepts only a single attachment at a time,
 * so its props omit `items` / `text`.
 *
 * Image / Video Composer renders bare — just the media with rounded
 * corners and a dismiss overlay, no surrounding bubble — so the draft
 * preview reads as an in-progress attachment instead of a sent
 * message. Sent / Received wrap the media in the shared bubble chrome.
 *
 * Image / Video / Pdf are interactive in every state (Composer, Sent,
 * Received) — clicks open the corresponding native lightbox `<dialog>`,
 * which centers the media at reasonable max dimensions (Escape and
 * backdrop click also dismiss). The Image viewer adds an explicit
 * download button to the chrome; the Video viewer relies on the
 * native `<video controls>` download menu, and the Pdf viewer
 * inherits the browser's built-in PDF download. Sibling-row Download
 * buttons on Pdf / File and the native `<audio>` controls expose
 * downloads outside the viewer too. The lightbox chrome is styled
 * with plain CSS (`.mes-media-viewer*`) so the package's shipped
 * stylesheet is enough to render the viewer correctly without a
 * Tailwind dependency in the consumer.
 *
 * # Lazy-loading defaults
 *
 * Media attachments bake in network-friendly defaults for long chat
 * histories and expose explicit escape hatches when a caller knows
 * better (e.g. a hero attachment that's already on-screen):
 *
 *   - **Image** — every `<img>` rendered on the bubble surface
 *     (Composer thumbnail, single + stacked tiles, `+N` overflow)
 *     ships with `loading="lazy" decoding="async"`. Override via the
 *     attachment's `loading` prop (or `ImageItem.loading` for per-tile
 *     control). The opened `ImageViewer` always eager-loads the
 *     active image so it appears immediately.
 *   - **Video** — the `<video>` rendered inside the `VideoViewer`
 *     defaults to `preload="none"`, so no video bytes are fetched
 *     until the user opens the viewer. Poster `<img>` thumbnails on
 *     the bubble surface are `loading="lazy" decoding="async"`.
 *     Override via the attachment's `preload` prop (or
 *     `VideoItem.preload` per item). Once the viewer is open the
 *     active item bumps to `preload="metadata"` so duration / the
 *     first frame appear immediately.
 *   - **Audio** — a single audio bubble defaults to
 *     `preload="metadata"` so the native player surfaces duration
 *     immediately. A stacked audio bubble (`items.length > 1`)
 *     defaults to `preload="none"` for every player so a thread of
 *     voice memos doesn't fan out N parallel metadata requests on
 *     first paint. Override via the attachment's `preload` prop
 *     (or `AudioItem.preload` per track).
 *   - **Pdf** / **File** — no inline media element to throttle; the
 *     bubble renders compact rows that download / open lazily on
 *     activation. No `loading` / `preload` props on these surfaces.
 */
const MessageAttachment = {
  Image: ImageAttachment,
  Video: VideoAttachment,
  Audio: AudioAttachment,
  Pdf: PdfAttachment,
  File: FileAttachment,
}

export default MessageAttachment

export type {
  ImageComposerProps,
  ImageSentProps,
  ImageReceivedProps,
  VideoComposerProps,
  VideoSentProps,
  VideoReceivedProps,
  AudioComposerProps,
  AudioSentProps,
  AudioReceivedProps,
  PdfComposerProps,
  PdfSentProps,
  PdfReceivedProps,
  FileComposerProps,
  FileSentProps,
  FileReceivedProps,
}
export type {
  ImageItem,
  ImageLoadingMode,
  VideoItem,
  PdfItem,
  AudioItem,
  FileItem,
  BubbleGroupPosition,
  MediaPreloadMode,
  MessageAttachmentBaseProps,
  MessageAttachmentState,
} from './types'
export { bubbleGroupPositionFromStream } from './types'
export {
  formatFileSize,
  getFileExtensionLabel,
  buildCompactMetaLabel,
} from './_shared/fileMeta'
