import type { ChatMessage, SessionSnapshot } from "../../../shared/types";
import type { ChatThread } from "./types";
import { tStatic } from "../i18n";

function getLastMessage(messages: ChatMessage[]): ChatMessage | null {
  if (messages.length === 0) return null;
  return messages.reduce((latest, current) =>
    current.createdAt > latest.createdAt ? current : latest,
  );
}

export function buildThreads(
  session: SessionSnapshot,
  meId: string | null,
  isBanker: boolean,
): ChatThread[] {
  const threads: ChatThread[] = [];
  const globalMessages = session.chats.filter((message) => message.groupId === null);
  threads.push({
    id: "global",
    name: tStatic("chat.global"),
    kind: "global",
    members: [],
    lastMessage: getLastMessage(globalMessages),
  });

  session.groups.forEach((group) => {
    if (!isBanker && meId && !group.memberIds.includes(meId)) {
      return;
    }
    const groupMessages = session.chats.filter((message) => message.groupId === group.id);
    let name = group.name;
    let kind: ChatThread["kind"] = "group";
    if (group.memberIds.length === 2) {
      const [first, second] = group.memberIds;
      if (isBanker || !meId) {
        const firstName =
          session.players.find((player) => player.id === first)?.name ??
          tStatic("common.player");
        const secondName =
          session.players.find((player) => player.id === second)?.name ??
          tStatic("common.player");
        name = `${firstName} & ${secondName}`;
        kind = "direct";
      } else {
        const otherId = first === meId ? second : first;
        const otherName =
          session.players.find((player) => player.id === otherId)?.name ??
          tStatic("common.player");
        name = otherName;
        kind = "direct";
      }
    }
    threads.push({
      id: group.id,
      name,
      kind,
      members: group.memberIds,
      lastMessage: getLastMessage(groupMessages),
    });
  });

  return threads.sort((a, b) => {
    const aTime = a.lastMessage?.createdAt ?? 0;
    const bTime = b.lastMessage?.createdAt ?? 0;
    return bTime - aTime;
  });
}

export function getThreadMessages(session: SessionSnapshot, threadId: string): ChatMessage[] {
  if (threadId === "global") {
    return session.chats.filter((message) => message.groupId === null).slice().reverse();
  }
  return session.chats.filter((message) => message.groupId === threadId).slice().reverse();
}

export function getLatestThreadTimestamp(session: SessionSnapshot, threadId: string): number | null {
  const messages =
    threadId === "global"
      ? session.chats.filter((message) => message.groupId === null)
      : session.chats.filter((message) => message.groupId === threadId);
  if (messages.length === 0) return null;
  return messages.reduce(
    (latest, message) => (message.createdAt > latest ? message.createdAt : latest),
    0,
  );
}

export function getUnreadThreadIds(
  session: SessionSnapshot,
  meId: string | null,
  isBanker: boolean,
  readState: Record<string, number>,
): Set<string> {
  const unread = new Set<string>();
  if (!meId) return unread;
  const allowed = new Set(
    buildThreads(session, meId, isBanker).map((thread) => thread.id),
  );
  session.chats.forEach((message) => {
    if (message.fromId === meId) return;
    const threadId = message.groupId ?? "global";
    if (!allowed.has(threadId)) return;
    const lastRead = readState[threadId] ?? 0;
    if (message.createdAt > lastRead) {
      unread.add(threadId);
    }
  });
  return unread;
}
