import { archiveAccountThread, listAccountThreads } from "./codex-history.js";

export async function archiveLogicalThread(
  config,
  accountId,
  threadId,
  {
    sessions = [],
    archiveThread = archiveAccountThread,
    listThreads = listAccountThreads
  } = {}
) {
  const session = sessions.find((item) => referencesThread(item, accountId, threadId));
  if (!session) return archiveThread(config, accountId, threadId);

  const configuredAccounts = new Set((config.accounts ?? []).map((account) => account.id));
  const refs = uniqueThreadRefs([
    ...(session.threadRefs ?? []),
    { accountId, threadId }
  ]).filter((ref) => configuredAccounts.has(ref.accountId));
  const activeRefs = await findActiveThreadRefs(config, refs, listThreads);

  for (const ref of activeRefs) {
    await archiveThread(config, ref.accountId, ref.threadId);
  }

  return { archived: true, ownerId: accountId, threadId };
}

async function findActiveThreadRefs(config, refs, listThreads) {
  const refsByAccount = new Map();
  for (const ref of refs) {
    if (!refsByAccount.has(ref.accountId)) refsByAccount.set(ref.accountId, []);
    refsByAccount.get(ref.accountId).push(ref);
  }

  const matches = await Promise.all([...refsByAccount].map(async ([accountId, accountRefs]) => {
    const remaining = new Set(accountRefs.map((ref) => ref.threadId));
    const active = new Set();
    const seenCursors = new Set();
    let cursor;

    do {
      const result = await listThreads(config, accountId, { cursor, archived: false });
      for (const thread of result.threads ?? []) {
        if (!remaining.delete(thread.id)) continue;
        active.add(thread.id);
      }
      const nextCursor = result.nextCursor;
      if (!nextCursor || seenCursors.has(nextCursor)) break;
      seenCursors.add(nextCursor);
      cursor = nextCursor;
    } while (remaining.size > 0);

    return accountRefs.filter((ref) => active.has(ref.threadId));
  }));

  return matches.flat();
}

function referencesThread(session, accountId, threadId) {
  if (session?.accountId === accountId && session?.codexThreadId === threadId) return true;
  return (session?.threadRefs ?? []).some((ref) =>
    ref.accountId === accountId && ref.threadId === threadId
  );
}

function uniqueThreadRefs(refs) {
  return [...new Map(refs
    .filter((ref) => typeof ref?.accountId === "string" && typeof ref?.threadId === "string")
    .map((ref) => [`${ref.accountId}:${ref.threadId}`, ref])).values()];
}
