import test from "node:test";
import assert from "node:assert/strict";
import {
  buildProjectGroups,
  formatThreadAge,
  nextProjectThreadLimit,
  projectlessThreads,
  recentThreads,
  visibleProjectThreads,
  shouldShowChatLoadMore
} from "./chats-projects.js";

test("shows only projects with chat activity", () => {
  const groups = buildProjectGroups([
    { id: "1", ownerId: "a", workspaceLabel: "Dashboard", updatedAt: "2026-06-29T10:00:00.000Z" },
    { id: "2", ownerId: "a", updatedAt: "2026-06-29T11:00:00.000Z" },
    { id: "3", ownerId: "b", workspaceLabel: "Dashboard", updatedAt: "2026-06-29T12:00:00.000Z" },
    { id: "4", ownerId: "a", workspaceLabel: "Job", updatedAt: "2026-06-29T09:00:00.000Z" }
  ], [{ id: "empty", label: "Empty" }]);

  assert.deepEqual(groups.map((group) => group.label), ["Dashboard", "Job"]);
  assert.deepEqual(groups[0].threads.map((thread) => thread.id), ["3", "1"]);
});

test("hides a project until it has activity newer than the hide time", () => {
  const threads = [{ id: "one", ownerId: "a", workspaceId: "workspace-a", workspaceLabel: "Alpha", updatedAt: "2026-07-14T01:00:00.000Z" }];
  const workspaces = [{ id: "workspace-a", label: "Alpha" }];
  const hiddenProjects = [{ projectKey: "workspace-a", hiddenAt: "2026-07-14T02:00:00.000Z" }];

  assert.deepEqual(buildProjectGroups(threads, workspaces, hiddenProjects), []);
  assert.equal(buildProjectGroups([
    { ...threads[0], updatedAt: "2026-07-14T03:00:00.000Z" }
  ], workspaces, hiddenProjects)[0].key, "workspace-a");
});

test("does not merge unknown history into a registered project with the same label", () => {
  const groups = buildProjectGroups([
    { id: "known", ownerId: "a", workspaceId: "known-id", workspaceLabel: "Shared", updatedAt: "2026-01-02T00:00:00.000Z" },
    { id: "unknown", ownerId: "b", workspaceLabel: "Shared", updatedAt: "2026-01-01T00:00:00.000Z" }
  ], [{ id: "known-id", label: "Shared" }]);

  assert.equal(groups.length, 2);
  assert.deepEqual(groups.map((group) => group.key), ["known-id", "label:Shared"]);
});

test("recent threads includes every chat in newest-first order", () => {
  const result = recentThreads([
    { id: "old", updatedAt: "2026-06-29T09:00:00.000Z" },
    { id: "new", updatedAt: "2026-06-29T12:00:00.000Z" },
    { id: "middle", updatedAt: "2026-06-29T10:00:00.000Z" }
  ]);

  assert.deepEqual(result.map((thread) => thread.id), ["new", "middle", "old"]);
});

test("project previews start at five chats and grow ten at a time", () => {
  const threads = Array.from({ length: 27 }, (_, index) => ({ id: String(index + 1) }));

  assert.deepEqual(visibleProjectThreads(threads).map((thread) => thread.id), ["1", "2", "3", "4", "5"]);
  assert.equal(nextProjectThreadLimit(undefined, threads.length), 15);
  assert.equal(nextProjectThreadLimit(15, threads.length), 25);
  assert.equal(nextProjectThreadLimit(25, threads.length), 27);
});

test("recent projectless chats exclude every chat assigned to a project", () => {
  const result = projectlessThreads([
    { id: "registered", workspaceId: "workspace-a", workspaceLabel: "Alpha", updatedAt: "2026-01-03T00:00:00.000Z" },
    { id: "desktop-project", workspaceLabel: "Desktop Project", updatedAt: "2026-01-02T00:00:00.000Z" },
    { id: "loose", updatedAt: "2026-01-01T00:00:00.000Z" }
  ]);

  assert.deepEqual(result.map((thread) => thread.id), ["loose"]);
});

test("pinned chats sort before newer unpinned chats", () => {
  const result = recentThreads([
    { id: "new", updatedAt: "2026-01-03T00:00:00.000Z" },
    { id: "pinned", pinned: true, updatedAt: "2026-01-01T00:00:00.000Z" },
    { id: "old", updatedAt: "2026-01-02T00:00:00.000Z" }
  ]);
  assert.deepEqual(result.map((thread) => thread.id), ["pinned", "new", "old"]);
});

test("load more is available only in a paginated top-level chat list", () => {
  assert.equal(shouldShowChatLoadMore("next-page", undefined), true);
  assert.equal(shouldShowChatLoadMore(null, undefined), false);
  assert.equal(shouldShowChatLoadMore("next-page", { key: "project-a" }), false);
});

test("formats localized thread age", () => {
  const now = Date.parse("2026-06-29T12:00:00.000Z");

  assert.equal(formatThreadAge("2026-06-29T06:00:00.000Z", now), "6h");
  assert.equal(formatThreadAge("2026-06-26T12:00:00.000Z", now), "3d");
  assert.equal(formatThreadAge("2026-06-29T11:42:00.000Z", now), "18m");
  assert.equal(formatThreadAge("2026-06-29T11:59:00.000Z", now, "ko"), "1분 전");
  assert.equal(formatThreadAge("2026-06-29T06:00:00.000Z", now, "ko"), "6시간 전");
  assert.equal(formatThreadAge("2026-06-26T12:00:00.000Z", now, "ko"), "3일 전");
});
