import { useEffect, useRef, type CSSProperties, type ReactNode } from 'react';
import { MessageBubble, type MessageBubbleProps } from './MessageBubble.js';
import { PromptComposer } from './PromptComposer.js';
import { useChat } from './useChat.js';
import type { Message, UseChatOptions } from './types.js';

export interface ChatStreamProps extends UseChatOptions {
  /** Render slot above the messages list (e.g. a header or model picker). */
  header?: ReactNode;
  /** Render slot below the composer (e.g. a disclaimer). */
  footer?: ReactNode;
  /** Slot to render when there are no messages yet. */
  emptyState?: ReactNode;
  /** Per-message custom renderer. Defaults to <MessageBubble />. */
  renderMessage?: (message: Message) => ReactNode;
  /** Forwarded to every <MessageBubble> when default renderer is used. */
  messageProps?: Omit<MessageBubbleProps, 'message'>;
  /** Placeholder shown inside <PromptComposer>. */
  placeholder?: string;
  /** Tailwind escape hatch. */
  className?: string;
  /** Inline style escape hatch. */
  style?: CSSProperties;
}

/**
 * `<ChatStream>` — opinionated composition of `useChat` +
 * `<MessageBubble>` + `<PromptComposer>`. The 80% path for any chat UI
 * in a ByteLyst product. Drop it in, point it at an endpoint, done.
 *
 * Behavior:
 *   - Auto-scrolls to bottom on new message (sticky-bottom pattern).
 *   - Shows Stop affordance while streaming.
 *   - Surfaces transport errors inline below the messages list.
 *   - Renders `emptyState` when there are zero messages.
 *
 * For more control, compose the primitives yourself — `useChat` returns
 * everything you need.
 */
export function ChatStream({
  header,
  footer,
  emptyState,
  renderMessage,
  messageProps,
  placeholder,
  className,
  style,
  ...chatOptions
}: ChatStreamProps) {
  const chat = useChat(chatOptions);
  const scrollRef = useRef<HTMLDivElement>(null);

  // Sticky-bottom scroll — only auto-scroll if the user was already at
  // (or near) the bottom. Otherwise their reading position is preserved.
  useEffect(() => {
    const el = scrollRef.current;
    if (!el) return;
    const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;
    if (distanceFromBottom < 80) {
      el.scrollTop = el.scrollHeight;
    }
  }, [chat.messages]);

  const messages = chat.messages;
  const showEmpty = messages.length === 0 && !chat.isLoading;

  return (
    <div
      data-testid="bl-chat-stream"
      className={className}
      style={{
        display: 'flex',
        flexDirection: 'column',
        height: '100%',
        minHeight: 0,
        gap: 'var(--bl-space-3, 12px)',
        ...style,
      }}
    >
      {header}

      <div
        ref={scrollRef}
        data-testid="bl-chat-messages"
        style={{
          flex: 1,
          minHeight: 0,
          overflowY: 'auto',
          display: 'flex',
          flexDirection: 'column',
          gap: 'var(--bl-space-3, 12px)',
          padding: 'var(--bl-space-2, 8px)',
        }}
      >
        {showEmpty
          ? emptyState
          : messages.map(message =>
              renderMessage ? (
                <span key={message.id}>{renderMessage(message)}</span>
              ) : (
                <MessageBubble key={message.id} message={message} {...messageProps} />
              ),
            )}

        {chat.error && (
          <div
            role="alert"
            data-testid="bl-chat-error"
            style={{
              padding: 'var(--bl-space-3, 12px)',
              borderRadius: 'var(--bl-radius-card, 12px)',
              background: 'var(--bl-danger-muted, rgba(239,68,68,0.1))',
              color: 'var(--bl-danger, #ef4444)',
              fontSize: '0.85rem',
            }}
          >
            {chat.error.message}
          </div>
        )}
      </div>

      <PromptComposer
        value={chat.input}
        onChange={chat.handleInputChange}
        onSubmit={chat.handleSubmit}
        disabled={chat.isLoading}
        showStop={chat.isLoading}
        onStop={chat.stop}
        placeholder={placeholder}
      />

      {footer}
    </div>
  );
}
