import type { UiMessage } from "@/stores/chat/ui-message";

import type { ChatState } from "../chat-state";

// Initial and subsequent history pages use the same bounded page size.
export const CHAT_HISTORY_LIMIT = 50;

export function applyHistoryLoadedOutput(
  output: {
    messages: UiMessage[];
  },
): Pick<ChatState, "messages" | "historyLoaded"> {
  return {
    messages: output.messages,
    historyLoaded: true,
  };
}

export function applyNetworkHistoryLoadedOutput(
  context: ChatState,
  output: {
    messages: UiMessage[];
    localDisplayIds: readonly string[];
    localCount: number;
    total: number;
    limit: number;
  },
): Pick<
  ChatState,
  | "messages"
  | "historyLoaded"
  | "networkHistoryLoaded"
  | "historyTotal"
  | "historyLimit"
  | "nextHistoryOffset"
  | "isLoadingMoreHistory"
> {
  const localDisplayIds = new Set(output.localDisplayIds);
  const networkDisplayIds = new Set(
    output.messages.map((message) => message.displayId),
  );
  const optimisticTail = context.messages.filter(
    (message) =>
      !localDisplayIds.has(message.displayId) &&
      !networkDisplayIds.has(message.displayId),
  );
  const historyLimit = normalizeHistoryLimit(output.limit);
  return {
    messages: [...output.messages, ...optimisticTail],
    historyLoaded: true,
    networkHistoryLoaded: true,
    historyTotal: Math.max(0, output.total),
    historyLimit,
    nextHistoryOffset: historyLimit,
    isLoadingMoreHistory: false,
  };
}

export function applyOlderHistoryLoadedOutput(
  context: ChatState,
  output: {
    messages: UiMessage[];
    offset: number;
    total: number;
    limit: number;
  },
): Pick<
  ChatState,
  | "messages"
  | "historyTotal"
  | "historyLimit"
  | "nextHistoryOffset"
  | "isLoadingMoreHistory"
> {
  const historyLimit = normalizeHistoryLimit(
    output.limit,
    context.historyLimit,
  );
  return {
    messages: prependUniqueHistoryMessages(context.messages, output.messages),
    historyTotal: Math.max(0, output.total),
    historyLimit,
    nextHistoryOffset: output.offset + historyLimit,
    isLoadingMoreHistory: false,
  };
}

export function canLoadMoreHistory(context: ChatState): boolean {
  return (
    context.historyLoaded &&
    !context.isLoadingMoreHistory &&
    context.nextHistoryOffset < context.historyTotal
  );
}

export function normalizeHistoryLimit(
  limit: number,
  fallback = CHAT_HISTORY_LIMIT,
): number {
  return Number.isFinite(limit) && limit > 0 ? Math.floor(limit) : fallback;
}

export function prependUniqueHistoryMessages(
  currentMessages: readonly UiMessage[],
  olderMessages: readonly UiMessage[],
): UiMessage[] {
  const existingIds = new Set(
    currentMessages.map((message) => message.displayId),
  );
  const pageIds = new Set<string>();
  const uniqueOlderMessages = olderMessages.filter((message) => {
    if (
      existingIds.has(message.displayId) ||
      pageIds.has(message.displayId)
    ) {
      return false;
    }
    pageIds.add(message.displayId);
    return true;
  });
  return [...uniqueOlderMessages, ...currentMessages];
}
