'use client';

import { useCallback, useEffect, useRef, useState } from 'react';

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

export interface UseChatUnreadOptions {
  /**
   * When true, unread state is auto-cleared (treated as "user is reading
   * the chat right now"). Pass your dock-open boolean here so the badge
   * resets the moment the user opens the chat.
   */
  open?: boolean;
  /**
   * Which message roles count as "unread". Defaults to `['assistant']` —
   * we only count inbound replies, not the user's own messages.
   */
  countRoles?: Array<ChatMessage['role']>;
}

export interface UseChatUnreadReturn {
  /** Most-recent inbound message since the last mark-as-read. */
  unread: ChatMessage | null;
  /** Total inbound messages since the last mark-as-read. */
  count: number;
  /** Manually clear the unread state. */
  markRead: () => void;
}

/**
 * Track inbound chat messages while the user isn't watching.
 *
 * Must be called **inside** the chat's `<ChatProvider>` (i.e. inside the
 * `children` of `ChatLauncher`, alongside `ChatRoot`).
 *
 * @example
 * ```tsx
 * function ChatRootWithUnreadBadge({ open, onUnread }: { open: boolean; onUnread: (m: ChatMessage | null) => void }) {
 *   const { unread, count, markRead } = useChatUnread({ open });
 *   useEffect(() => onUnread(unread), [unread, onUnread]);
 *   // pass `count` to your FAB badge via the host's state
 *   return <ChatRoot transport={transport} />;
 * }
 * ```
 *
 * For end-to-end wiring with `<ChatLauncher unreadMessage onMarkRead>`,
 * see the `Launcher / WithLivePush` story.
 */
export function useChatUnread(opts: UseChatUnreadOptions = {}): UseChatUnreadReturn {
  const { open = false, countRoles = ['assistant'] } = opts;
  const ctx = useChatContext();

  const [lastSeenId, setLastSeenId] = useState<string | null>(null);
  // On first mount, treat the current tail as already seen so old history
  // doesn't immediately register as unread.
  const initialized = useRef(false);
  useEffect(() => {
    if (initialized.current) return;
    initialized.current = true;
    const tail = ctx.messages[ctx.messages.length - 1];
    setLastSeenId(tail?.id ?? null);
  }, [ctx.messages]);

  // While the dock is open, auto-advance the seen pointer to the tail so
  // count stays at 0.
  useEffect(() => {
    if (!open) return;
    const tail = ctx.messages[ctx.messages.length - 1];
    setLastSeenId(tail?.id ?? null);
  }, [open, ctx.messages]);

  // Compute unread tail since `lastSeenId`.
  const seenIdx = lastSeenId
    ? ctx.messages.findIndex((m) => m.id === lastSeenId)
    : -1;
  const after = seenIdx === -1 ? ctx.messages : ctx.messages.slice(seenIdx + 1);
  const inbound = after.filter((m) => countRoles.includes(m.role));
  const unread = inbound.length > 0 ? inbound[inbound.length - 1]! : null;

  const markRead = useCallback(() => {
    const tail = ctx.messages[ctx.messages.length - 1];
    setLastSeenId(tail?.id ?? null);
  }, [ctx.messages]);

  return { unread, count: inbound.length, markRead };
}
