import { globalStyle, style } from '@vanilla-extract/css';
import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
import { DefaultReset, color, config, toRem } from 'folds';

// Bubble layout — the simple 1:1 DM chat (assistant-style, like the AI-bot chat):
// the peer's turn is plain full-width text, the user's turn is a right-aligned
// bubble on the composer surface. No rail / dot / nick / avatar. A muted
// per-message timestamp sits in the bubble corner (own) or after the text (peer),
// and the last own message can carry a read-status line below it.

// Per-message vertical rhythm. Continuation rows (same sender) tuck tighter.
const ROW_GAP = toRem(2);
const SENDER_GAP = config.space.S300;

// Row = column stack {bubble|text, reactions, status}, aligned to the sender's
// side. Full-width so the whole row is a comfortable tap target for the rail.
export const Row = recipe({
  base: [
    DefaultReset,
    {
      display: 'flex',
      flexDirection: 'column',
      gap: ROW_GAP,
      minWidth: 0,
      width: '100%',
      // A first-of-run row gets a little more air above it; continuation rows
      // collapse it so a same-sender burst reads as one cluster.
      marginTop: SENDER_GAP,
    },
  ],
  variants: {
    own: {
      true: { alignItems: 'flex-end' },
      false: { alignItems: 'flex-start' },
    },
    collapsed: {
      true: { marginTop: 0 },
    },
  },
  defaultVariants: { own: false },
});

export type BubbleRowVariants = RecipeVariants<typeof Row>;

// Own bubble — composer-tone surface holding the message body. For a single
// message the enclosing LineWrapOwn caps the bubble + side-time unit at 85%; for
// a grouped (same-minute series) tail the time sits BELOW and the bubble fills
// its (already short, right-aligned) content width.
export const OwnBubble = style({
  display: 'flex',
  flexDirection: 'column',
  alignItems: 'stretch',
  maxWidth: '100%',
  minWidth: 0,
  padding: `${config.space.S200} ${config.space.S400}`,
  borderRadius: config.radii.R400,
  backgroundColor: color.Surface.Container,
  color: color.Surface.OnContainer,
  wordBreak: 'break-word',
});

// Peer turn — plain text capped to a comfortable reading measure (~70ch),
// like the AI-bot chat, so long prose doesn't stretch edge-to-edge on desktop.
export const PeerText = style({
  display: 'flex',
  flexDirection: 'column',
  alignItems: 'flex-start',
  maxWidth: toRem(768),
  minWidth: 0,
  color: color.Surface.OnContainer,
  wordBreak: 'break-word',
});

// Media / voice rows drop the bubble chrome — the media shell / voice card draws
// its own visuals. `width: fit-content` so the block shrinks to the media/voice
// card and the parent Row can align it (own right, peer left); `width: 100%`
// here would fill the band and defeat that alignment. The image shell is itself
// `width: fit-content` (StreamMedia.css) and the voice card is bounded by its own
// max-width, so both size correctly inside this shrink-wrap.
export const MediaPlain = style({
  display: 'flex',
  flexDirection: 'column',
  minWidth: 0,
  width: 'fit-content',
  maxWidth: '100%',
});

// Editing: the body is the composer card itself (wrapped in ChatComposer by the
// caller) — full width, no bubble background of our own.
export const EditContent = style({
  width: '100%',
  minWidth: 0,
});

// Tap-rail open (or context menu / emoji board open) → the message reads as
// «selected», the same affordance long-press gives. A soft brand ring rather
// than a fill so it works over both the bubble and bare peer text / media.
export const Selected = style({
  outline: `${toRem(2)} solid ${color.Primary.Main}`,
  outlineOffset: toRem(2),
  borderRadius: config.radii.R400,
});

// Horizontal wrapper for a SINGLE text message: body + side timestamp on one
// row. Order is set in JSX: own → [time][bubble] (time on the inner/left side),
// peer → [text][time] (inner/right). `align-items: flex-end` drops the stamp onto
// the bubble's bottom edge. The Row aligns the whole wrap to the message side.
export const LineWrap = style({
  display: 'flex',
  alignItems: 'flex-end',
  gap: toRem(6),
  minWidth: 0,
});

// Cap the own message + time unit so a long single bubble doesn't span the band.
export const LineWrapOwn = style({ maxWidth: '85%' });
export const LineWrapPeer = style({ maxWidth: '100%' });

// Muted timestamp base — a fixed label that never shrinks (the body wraps
// first). Placement (beside vs below) comes from the modifier classes.
export const Meta = style({
  flexShrink: 0,
  fontSize: toRem(11),
  lineHeight: toRem(14),
  color: color.Surface.OnContainer,
  opacity: 0.55,
  fontVariantNumeric: 'tabular-nums',
  whiteSpace: 'nowrap',
});

// Side placement (single text messages): beside the bubble, lifted off the very
// bottom so the stamp reads near the last text line, not the padding edge.
export const MetaSide = style({
  paddingBottom: toRem(3),
});

// Below placement (media + grouped same-minute series tail): a small gap under
// the bubble / media card, aligned to the message side by the parent Row.
export const MetaBelow = style({
  marginTop: toRem(2),
});

globalStyle(`${Meta} time`, {
  display: 'block',
  fontSize: toRem(11),
  lineHeight: toRem(14),
});

// Read-status text under the last own message (Sending… / Sent / Read / failed).
export const Status = style({
  fontSize: toRem(11),
  lineHeight: toRem(14),
  color: color.Surface.OnContainer,
  opacity: 0.6,
  whiteSpace: 'nowrap',
});

export const StatusFailed = style({
  color: color.Critical.Main,
  opacity: 1,
});

// Reactions / thread-summary wrappers — float on the page background, aligned
// to the message side by the parent Row.
export const Slot = style({
  maxWidth: '100%',
  minWidth: 0,
});

// Rail-less system notice (room name/topic/avatar changes) for the bubble DM:
// a centred, muted one-liner — no rail, no dot, no bubble.
export const Sysline = style({
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
  gap: config.space.S200,
  padding: `${toRem(2)} ${config.space.S400}`,
  minWidth: 0,
});

export const SyslineIcon = style({
  opacity: 0.5,
  flexShrink: 0,
});

export const SyslineBody = style({
  fontSize: toRem(12),
  color: color.Surface.OnContainer,
  opacity: 0.55,
  fontStyle: 'italic',
  overflow: 'hidden',
  whiteSpace: 'nowrap',
  textOverflow: 'ellipsis',
  minWidth: 0,
});

export const SyslineTime = style({
  flexShrink: 0,
  fontSize: toRem(11),
  color: color.Surface.OnContainer,
  opacity: 0.45,
  fontVariantNumeric: 'tabular-nums',
  whiteSpace: 'nowrap',
});

globalStyle(`${SyslineTime} time`, {
  display: 'block',
  fontSize: toRem(11),
});
