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

// Shared with the call-horseshoe surface so both ends of the chat
// (top profile rail, bottom call rail) read with identical geometry.
export const HORSESHOE_RADIUS_PX = 32;
export const HORSESHOE_GAP_PX = 12;

// Outer container — flex column hosting the silhouette (panel +
// header live inside) and the chat body below. `overflow: hidden`
// clips the chat body's rounded top corners against the container's
// own edges when the user-card rail is open and the chatBody margin-
// top void gap opens up; without this clip the rounded-corner cut
// areas would reveal whatever's behind the chat column instead of
// the horseshoe void colour painted by `containerStyle`.
export const container = style({
  position: 'relative',
  display: 'flex',
  flex: 1,
  flexDirection: 'column',
  minWidth: 0,
  minHeight: 0,
  overflow: 'hidden',
});

// === Silhouette === Single-element wrapper that owns the
// rounded-bottom geometry shared by the user-card panel and the chat
// header. Both live as direct children of this one box, so a single
// `border-bottom-{left,right}-radius` cuts the bottom of the
// combined block — there's no «hand-off» from header-bottom-radius
// to panel-bottom-radius mid-drag because there's only one radius
// to begin with. Replaces the legacy `horseshoeEmerge` curve that
// ramped two separate radii in the last 15% of drag.
//
// `overflow: hidden` is what makes the radius actually crop content
// (without it the rounded bottom would just be an SVG-like outline
// behind opaque children). The flex column stacks panelViewport (top)
// over headerViewport (bottom), so the silhouette's bottom edge
// always coincides with whichever child is currently last-visible —
// which is exactly the "bottom edge of the silhouette" the rounding
// sits on.
export const silhouette = style({
  display: 'flex',
  flexDirection: 'column',
  flexShrink: 0,
  overflow: 'hidden',
  backgroundColor: color.Background.Container,
  willChange: 'border-bottom-left-radius, border-bottom-right-radius',
});

// === Panel viewport === Variable-height clipping window for the
// fixed-height panel content (railHeight tall, anchored bottom:0).
// As the viewport grows from 0 to railHeight during drag, more of
// panelContent is revealed from its bottom edge upward
// (handle → scroll content → avatar top) — equivalent visual to the
// legacy `transform: translateY(expandedPx - railHeight)` trick that
// shifted the whole panel down from above viewport.
//
// `touchAction: pan-y` keeps the panel-internal scroll responsive;
// the drag-up close gesture preventDefault's explicitly inside the
// touchmove handler. `userSelect: none` keeps mouse drag clean — on
// the pointer path a left-button drag would otherwise race the
// browser's native text-selection drag (selection highlight grows
// during the gesture and the user has to click once to deselect
// after release).
export const panelViewport = style({
  position: 'relative',
  width: '100%',
  overflow: 'hidden',
  willChange: 'height',
  touchAction: 'pan-y',
  userSelect: 'none',
});

// Anchor at the TOP of `panelViewport` so the card slides downward as
// `panelViewport.height` grows: hero avatar visible first, info rows
// behind it, drag handle last. Previously `bottom: 0` made the handle
// reveal first and the hero last — which read as "dark rising from the
// chat header" once the silhouette also extended through the status-bar
// zone above. Trade-off: drag handle is hidden mid-drag, only visible
// when fully open; the panel surface stays drag-sensitive throughout.
//
// `padding-top: var(--vojo-safe-top)` keeps the user-card content (hero
// avatar + info rows) clear of the Android status-bar icons in the
// open state. The padding zone shows the silhouette's bg
// (`Background.Container`, #0d0e11) through panelContent's transparent
// background, so the status-bar zone reads as part of the dark user
// card when the panel is open.
//
// `box-sizing: border-box` makes the inline `height: ${railHeightPx}`
// include the safe-top padding — so the rail measured in
// `RoomViewProfilePanel.tsx` (content + padTop + handle) exactly
// matches the actual visible height. Without `border-box` the height
// would be content-area only and the rail would visually overshoot by
// `var(--vojo-safe-top)`, leaving an unfilled gap at the bottom.
export const panelContent = style({
  position: 'absolute',
  top: 0,
  left: 0,
  right: 0,
  boxSizing: 'border-box',
  paddingTop: 'var(--vojo-safe-top, 0px)',
});

export const panelInner = style({
  display: 'flex',
  flexDirection: 'column',
  height: '100%',
});

// Holds the user-card content. `overflow-y` is driven inline from
// `RoomViewProfilePanel.tsx` based on whether the measured content
// height exceeds the safety cap (`MAX_RAIL_FRACTION × viewport`):
//
//   • Common fit case (content ≤ cap) → `overflow-y: hidden`. The
//     rail is sized to content, so there's literally nothing to
//     scroll. This is the user's explicit «запретил бы драгу внутри»
//     ask — no drag-inside-drag inside the user card.
//   • Rare overflow case (e.g. stacked moderation alerts) → switches
//     to `auto`, so the user can still reach the clipped tail.
//
// Scrollbar chrome is suppressed either way; the auto case relies on
// the standard touch / wheel scroll affordances.
export const panelScroll = style({
  flex: 1,
  minHeight: 0,
  scrollbarWidth: 'none',
  selectors: {
    '&::-webkit-scrollbar': {
      display: 'none',
    },
  },
});

// Bottom drag handle — visible cue that the panel is draggable. The
// whole panel surface is also drag-sensitive (see TSX), but the
// handle stays as an obvious affordance for users who don't try the
// surface gesture.
export const panelHandle = style({
  flexShrink: 0,
  height: toRem(20),
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
  cursor: 'grab',
  touchAction: 'none',
  selectors: {
    '&:active': { cursor: 'grabbing' },
  },
});

export const panelHandleBar = style({
  width: toRem(36),
  height: toRem(4),
  borderRadius: toRem(4),
  backgroundColor: color.Surface.ContainerLine,
});

// Avatar full-view mode — fills the panel content area with the
// user's avatar at full size when the user taps the avatar inside
// the open panel. Click reverts to the regular profile content.
export const avatarFullView = style({
  width: '100%',
  height: '100%',
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
  cursor: 'pointer',
  position: 'relative',
  background: 'transparent',
  border: 'none',
  padding: 0,
});

export const avatarFullImage = style({
  width: '100%',
  height: '100%',
  objectFit: 'cover',
});

export const avatarFullFallback = style({
  width: '100%',
  height: '100%',
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
  fontSize: toRem(96),
  fontWeight: 600,
  color: color.Surface.Container,
  textTransform: 'uppercase',
});

// === Header viewport === Holds the chat header as the silhouette's
// bottom child. Animated via an explicit `height` set inline (driven
// by `(1 - expandedFraction) * headerNaturalHeight`, where
// `headerNaturalHeight` is measured via `useLayoutEffect` +
// `ResizeObserver` on the inner block). The legacy
// `grid-template-rows: 1fr → 0fr` trick was abandoned because Folds
// `<Header size="600">` enforces a `min-height` that prevented the
// grid track from collapsing to 0 — leaving a light-blue strip at
// the bottom of the user card. `overflow: hidden` keeps the chat
// header content clipped while the viewport height interpolates.
// `userSelect: none` keeps a mouse drag-down-to-open gesture from
// racing native text-selection on the chat title — same rationale
// as on `panelViewport`.
export const headerViewport = style({
  flexShrink: 0,
  overflow: 'hidden',
  willChange: 'height',
  userSelect: 'none',
});

// `padding-top: var(--vojo-safe-top)` pushes the chat header's content
// (back arrow, avatar, name) below the Android status-bar icons in
// edge-to-edge mode — `#root` no longer reserves the inset itself
// (src/index.css), so the chat header would otherwise land directly
// under the system icons. The padding zone is painted with
// `SurfaceVariant.Container` (the chat-header bg below it) so the
// visible strip against the status-bar icons reads as one continuous
// header band — no seam at the inset boundary.
//
// `box-sizing: border-box` is load-bearing for the height animation
// that `headerViewport` runs (see comment there): when the outer height
// reaches 0 px on full rail-open, the `padding-top` is included in the
// 0-tall box and the SurfaceVariant strip collapses with it. With
// `content-box` it would persist as a `var(--vojo-safe-top)`-tall band
// at the bottom of the user card.
export const headerViewportInner = style({
  boxSizing: 'border-box',
  minHeight: 0,
  overflow: 'hidden',
  paddingTop: 'var(--vojo-safe-top, 0px)',
  backgroundColor: color.SurfaceVariant.Container,
});

// === Chat body === Timeline + input below the silhouette. The
// rounded top corners and the `margin-top` void gap appear together
// with the silhouette's rounded bottom — all three are driven by the
// same `horseshoeRamp` (live formula while finger-dragging, binary
// with CSS transition during release animation), so the two horseshoes
// and the void emerge in lockstep at drag-start without any per-element
// «emerge curve» of their own.
export const chatBody = style({
  display: 'flex',
  flex: 1,
  flexDirection: 'column',
  minWidth: 0,
  minHeight: 0,
  willChange: 'margin-top, border-top-left-radius, border-top-right-radius',
});
