'use client';

import { type RefObject, type ReactNode, forwardRef, useCallback } from 'react';

import { cn } from '@djangocfg/ui-core/lib';
import { Spinner } from '@djangocfg/ui-core/components';

import type { ChatMessage } from '../types';
import { useChatContextOptional } from '../context';
import { MessageBubble } from './MessageBubble';

export interface MessageListProps {
  messages?: ChatMessage[];
  renderItem?: (m: ChatMessage, i: number) => ReactNode;
  renderEmpty?: () => ReactNode;
  isLoadingMore?: boolean;
  topSentinelRef?: RefObject<HTMLDivElement | null>;
  bottomRef?: RefObject<HTMLDivElement | null>;
  className?: string;
  itemClassName?: string;
}

export const MessageList = forwardRef<HTMLDivElement, MessageListProps>(function MessageList(
  {
    messages: messagesProp,
    renderItem,
    renderEmpty,
    isLoadingMore: isLoadingMoreProp,
    topSentinelRef,
    bottomRef,
    className,
    itemClassName,
  },
  ref,
) {
  const ctx = useChatContextOptional();
  const messages = messagesProp ?? ctx?.messages ?? [];
  const isLoadingMore = isLoadingMoreProp ?? ctx?.isLoadingMore ?? false;

  const defaultRenderItem = useCallback(
    (m: ChatMessage) => (
      <div className={itemClassName} key={m.id}>
        <MessageBubble
          message={m}
          onCopy={() => copy(m.content)}
          onRegenerate={ctx ? () => void ctx.regenerate(m.id) : undefined}
          onDelete={ctx ? () => ctx.deleteMessage(m.id) : undefined}
        />
      </div>
    ),
    [itemClassName, ctx],
  );

  const itemRenderer = renderItem ?? defaultRenderItem;

  return (
    <div
      ref={ref}
      role="log"
      aria-live="polite"
      aria-atomic="false"
      className={cn('flex-1 overflow-y-auto', className)}
    >
      <div ref={topSentinelRef} aria-hidden />
      {isLoadingMore ? (
        <div className="flex justify-center py-2">
          <Spinner className="size-4 text-muted-foreground" />
        </div>
      ) : null}
      {messages.length === 0
        ? renderEmpty?.() ?? null
        : messages.map((m, i) => itemRenderer(m, i))}
      <div ref={bottomRef} aria-hidden />
    </div>
  );
});

function copy(text: string) {
  if (typeof navigator !== 'undefined' && navigator.clipboard) {
    void navigator.clipboard.writeText(text);
  }
}
