/**
 * Message blocks — typed, serializable rich-content slots.
 *
 * A `ChatMessage` may carry `blocks: MessageBlock[]`. Each block is a
 * discriminated union member keyed by `kind`. Payloads are plain JSON
 * (no Date, no Float32Array, no React nodes) so blocks survive history
 * persistence and SSE transport. See `@docs/message-blocks.md`.
 */

import type { LinkPreviewData } from '../../../common/link-preview';
import type { MapBlockPayload } from '../../../common/blocks';

/** Spaciousness hint forwarded from the bubble to renderers. */
export type BlockAppearance = 'compact' | 'full';

interface BlockBase {
  /** Stable id — used as React key and for memo diffing. */
  id: string;
  /** Optional caption rendered above the block. */
  caption?: string;
}

export interface TextBlock extends BlockBase {
  kind: 'text';
  text: string;
}

export interface MarkdownBlock extends BlockBase {
  kind: 'markdown';
  markdown: string;
}

export interface AudioBlock extends BlockBase {
  kind: 'audio';
  src: string;
  title?: string;
  artist?: string;
  cover?: string;
  /** `compact` → AudioPlayer variant. */
  variant?: 'default' | 'compact';
}

export interface VideoBlock extends BlockBase {
  kind: 'video';
  /** Raw URL string — VideoPlayer auto-classifies YouTube/Vimeo/HLS/MP4. */
  src: string;
  poster?: string;
  title?: string;
  aspectRatio?: number | 'auto' | 'fill';
}

export interface ImageBlock extends BlockBase {
  kind: 'image';
  src: string;
  alt?: string;
  /** When true → zoom/pan ImageViewer; else a plain `<img>`. */
  interactive?: boolean;
}

export interface GalleryBlock extends BlockBase {
  kind: 'gallery';
  items: Array<{ id: string; src: string; thumbnail?: string; alt?: string }>;
}

/**
 * Map block — a chat message map. The serializable map SHAPE (center / zoom /
 * basemap / terrain / markers / routes / polygons) is the shared
 * `MapBlockPayload` (defined once in `common/blocks/types.ts`) so the chat
 * map and the NotionEditor `mapBlock` node can't drift. Chat adds only the
 * chat-specific `userLocation` opt-in on top.
 */
export interface MapBlock extends BlockBase, MapBlockPayload {
  kind: 'map';
  /**
   * Opt in to the map's "show my location" chip (privacy-sensitive).
   *
   * This is a plain boolean OPT-IN flag, **not** coordinates — the browser
   * supplies the live position; we never bake lat/lng into the serialized
   * block. Default **off**: only set `true` when the host wants this chat
   * map to offer locate-me. When `true` it surfaces the toolbar locate-me
   * chip (forwarded to `MapContainer`'s `geolocate` prop); the user must
   * still grant the OS location permission, and nothing is requested until
   * they press the chip. Requires a secure context (HTTPS / localhost).
   * @default false
   */
  userLocation?: boolean;
}

export interface JsonBlock extends BlockBase {
  kind: 'json';
  data: unknown;
  /** JsonTree display mode. */
  mode?: 'full' | 'compact' | 'inline';
}

export interface MermaidBlock extends BlockBase {
  kind: 'mermaid';
  chart: string;
}

export interface CodeBlock extends BlockBase {
  kind: 'code';
  code: string;
  language: string;
}

/**
 * Code-diff block — wraps the `DiffViewer` tool. Provide EITHER
 * `oldCode` + `newCode` (the viewer runs an internal LCS diff) OR a
 * pre-computed unified `patch` string. `layout` pins side-by-side
 * (`split`) vs single-column (`unified`); when omitted it follows the
 * bubble appearance (compact → unified, full → split).
 */
export interface DiffBlock extends BlockBase {
  kind: 'diff';
  oldCode?: string;
  newCode?: string;
  patch?: string;
  language?: string;
  layout?: 'split' | 'unified';
}

/**
 * Link-preview (URL unfurl) card — favicon + og:image + title/description/
 * site name, Notion/Telegram style. Either the metadata is already
 * resolved (`data`), or only `url` is given and the host's
 * `resolveLinkPreview` resolver fills it in lazily. See
 * `common/link-preview/types.ts` for the data contract (the browser cannot
 * fetch meta tags itself — resolution is a host concern).
 */
export interface LinkBlock extends BlockBase {
  kind: 'link';
  /** The URL to preview (and link to). */
  url: string;
  /** Pre-resolved metadata. When absent, the host resolver is used. */
  data?: LinkPreviewData;
}

/**
 * Escape hatch for host-defined block types. The built-in registry
 * renders it as the unknown-kind fallback unless the host registers a
 * `custom` renderer that switches on `name`.
 */
export interface CustomBlock extends BlockBase {
  kind: 'custom';
  /** Host-defined sub-type, dispatched by the host's own renderer. */
  name: string;
  payload: unknown;
}

export type MessageBlock =
  | TextBlock
  | MarkdownBlock
  | AudioBlock
  | VideoBlock
  | ImageBlock
  | GalleryBlock
  | MapBlock
  | JsonBlock
  | MermaidBlock
  | CodeBlock
  | DiffBlock
  | LinkBlock
  | CustomBlock;

/** The discriminant literal — `'audio' | 'video' | …`. */
export type MessageBlockKind = MessageBlock['kind'];
