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

// 40px circular avatar — Discord's cozy-mode avatar size. Consumers override
// the folds preset via inline style; the shared `CHANNEL_AVATAR_PX` constant
// keeps the CSS slot width and the inline override in sync.
export const CHANNEL_AVATAR_PX = 40;
const ChannelAvatarWidth = toRem(CHANNEL_AVATAR_PX);

// Discord cozy-mode geometry: avatar 16px from the list edge, 16px gap to the
// content, so the message column starts at 16 + 40 + 16 = 72px.
const ChannelEdgePad = toRem(16);
const ChannelAvatarGap = toRem(16);

export const ChannelRow = style({
  display: 'flex',
  alignItems: 'flex-start',
  gap: ChannelAvatarGap,
  // Span the full message-column width so the hover highlight runs edge-to-edge
  // like Discord: cancel MessageBase's S400/S200 horizontal padding with negative
  // margins, then re-add the 16px avatar gutter as paddingLeft (so the avatar's
  // left edge lands 16px from the column edge — Discord cozy). NB: the column is
  // the centred BubbleTimelineBand, so that edge is the band's content edge, not
  // the screen edge (the band adds 12px native / 40px desktop outside this).
  marginLeft: `calc(-1 * ${config.space.S400})`,
  marginRight: `calc(-1 * ${config.space.S200})`,
  paddingLeft: ChannelEdgePad,
  paddingRight: ChannelEdgePad,
  // Tight vertical rhythm (Discord stacks lines on line-height); group
  // separation comes from MessageBase's `space` marginTop on the run head.
  paddingTop: toRem(2),
  paddingBottom: toRem(2),
  minWidth: 0,
  // Hover bg subtle so adjacent rows still read as distinct units. `@media
  // (hover: hover)` keeps this inert on touch where there's no pointer.
  '@media': {
    '(hover: hover) and (pointer: fine)': {
      selectors: {
        '&:hover': {
          backgroundColor: color.SurfaceVariant.Container,
        },
      },
    },
  },
});

// Fixed-width slot keeps the body column aligned across collapsed rows
// (where `avatar` is `undefined` — the slot still occupies `ChannelAvatarWidth`,
// so the body's left edge stays put).
export const ChannelAvatarSlot = style({
  width: ChannelAvatarWidth,
  flexShrink: 0,
  display: 'flex',
  justifyContent: 'center',
  paddingTop: toRem(2),
});

export const ChannelBody = style({
  flex: 1,
  minWidth: 0,
  display: 'flex',
  flexDirection: 'column',
  gap: config.space.S100,
});

export const ChannelHeader = style({
  display: 'flex',
  alignItems: 'baseline',
  gap: config.space.S200,
  minWidth: 0,
});

export const ChannelMessageBody = style({
  minWidth: 0,
});

export const ChannelReactions = style({
  minWidth: 0,
  marginTop: config.space.S100,
});

export const ChannelThreadSummary = style({
  minWidth: 0,
  marginTop: config.space.S100,
});

// Sysline (membership / room.create / pinned-events). Compact single
// row aligned with the body gutter — the sysline sits where messages'
// body would, indented past the avatar slot, so the column reads
// continuous.
export const ChannelSysline = style({
  // Indent past the avatar gutter so the sysline body aligns with the message
  // body column (72px). The sysline sits inside MessageBase's S400 (16px) left
  // pad (it has no edge-to-edge negative margin), so paddingLeft = avatar (40)
  // + gap (16) = 56 lands the content at 16 + 56 = 72px.
  paddingLeft: `calc(${ChannelAvatarWidth} + ${ChannelAvatarGap})`,
  paddingRight: config.space.S200,
  paddingTop: config.space.S100,
  paddingBottom: config.space.S100,
  color: color.SurfaceVariant.OnContainer,
});

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

export const ChannelSyslineBody = style({
  minWidth: 0,
  flex: 1,
});

// Bubble chrome applied when `ChannelLayout` is invoked with
// `headerInBubble` (thread drawer and channels main timeline pass it).
// Mirrors `StreamBubble` from the DM timeline so a channel row reads
// like a chat-bubble cluster: dark `Surface.Container` card with an
// asymmetric notch corner per `data-own`, sized `fit-content` so short
// bubbles shrink-wrap instead of stretching across the column.
// Reactions and the thread-summary card live as siblings of the body
// in `ChannelLayout`, so they stay OUTSIDE the bubble — identical
// composition to Stream. The `[data-bubble="true"]` row marker keeps
// the un-bubbled channel/sysline layout (pre-redesign callers) opt-in
// rather than forcing the look on every consumer.
globalStyle(`${ChannelRow}[data-bubble="true"] ${ChannelMessageBody}`, {
  backgroundColor: color.Surface.Container,
  color: color.SurfaceVariant.OnContainer,
  border: `1px solid ${color.Surface.ContainerLine}`,
  paddingTop: config.space.S200,
  paddingBottom: config.space.S200,
  paddingLeft: toRem(15),
  paddingRight: toRem(15),
  display: 'inline-block',
  width: 'fit-content',
  maxWidth: '100%',
  minWidth: 0,
  position: 'relative',
  zIndex: 1,
  // Clips the thread-summary footer's hover bg against the bubble's
  // rounded BR/BL corners — without it the rectangular hover paint
  // punches past the curve. No outflow content lives inside the bubble
  // (option bar, reactions are siblings on the row) so clipping is
  // safe.
  overflow: 'hidden',
});

// Asymmetric corner per `data-own` — own messages flatten BOTTOM-LEFT
// (4px), incoming messages flatten TOP-LEFT. Same pattern as
// `StreamBubble.own`/`StreamBubble.others`.
globalStyle(`${ChannelRow}[data-bubble="true"][data-own="true"] ${ChannelMessageBody}`, {
  borderRadius: `${toRem(16)} ${toRem(16)} ${toRem(16)} ${toRem(4)}`,
});

globalStyle(`${ChannelRow}[data-bubble="true"][data-own="false"] ${ChannelMessageBody}`, {
  borderRadius: `${toRem(4)} ${toRem(16)} ${toRem(16)} ${toRem(16)}`,
  // Peer (not-own) bubble bg for the channel layout — its own var. (The 1-1
  // Stream layout's incoming bubble instead binds to color.Surface.Container,
  // the composer surface.) Covers channels main timeline AND thread drawer
  // (both pass `headerInBubble`, so `data-bubble="true"` fires).
  backgroundColor: 'var(--vojo-peer-bubble-bg)',
});

// Small gap so the in-bubble header (username + time) doesn't sit flush
// against the first line of message text. Matches the Stream layout's
// `StreamName` 2px marginBottom.
globalStyle(`${ChannelRow}[data-bubble="true"] ${ChannelHeader}[data-in-bubble="true"]`, {
  marginBottom: toRem(2),
});

// Thread-summary footer rendered INSIDE the bubble (rather than as a
// separate pill below). Negative L/R margin (matches the bubble's
// `paddingLeft/Right: 15px`) stretches the wrapper to the bubble's
// inner border edge so the 1px top rule reads as a section divider
// spanning the whole bubble. Negative `marginBottom` cancels the
// bubble's S200 bottom pad so the footer flushes against the bubble's
// rounded bottom edge — bubble + summary read as one card with a
// horizontal rule splitting them.
//
// The footer body keeps no own border/radius — it inherits the bubble's
// bottom corners via clipping (`ChannelMessageBody` itself doesn't
// `overflow: hidden`, but the rounded bottom of the bubble visually
// caps the footer anyway because the divider line never reaches the
// curved corner pixel).
export const ChannelBubbleThreadSummary = style({
  marginTop: config.space.S200,
  marginLeft: toRem(-15),
  marginRight: toRem(-15),
  marginBottom: `calc(-1 * ${config.space.S200})`,
  borderTop: `1px solid ${color.Surface.ContainerLine}`,
});

// Footer button — strip the original ThreadSummaryCard pill chrome
// (own bg, radius, padding, max-width) so it reads as a flush bubble
// footer. Click target expands to the full footer width. Hover paints
// a subtle `SurfaceVariant.Container` shade that contrasts against
// the bubble's `Surface.Container` bg, signalling tappable footer
// without the pill silhouette returning.
globalStyle(`${ChannelBubbleThreadSummary} > button`, {
  display: 'flex',
  width: '100%',
  maxWidth: 'none',
  borderRadius: 0,
  backgroundColor: 'transparent',
  padding: `${config.space.S200} ${toRem(15)}`,
});

globalStyle(`${ChannelBubbleThreadSummary} > button:hover`, {
  backgroundColor: color.SurfaceVariant.Container,
});

globalStyle(`${ChannelBubbleThreadSummary} > button:focus-visible`, {
  // Inset the focus ring slightly so it doesn't punch through the
  // bubble's rounded bottom corners on the BR/BL when the row is
  // either own or incoming.
  outlineOffset: toRem(-2),
});
