import { expect, test } from "@playwright/test";

import {
  THREAD_WITH_HISTORY,
  THREAD_WITH_MARKDOWN,
  THREAD_WITH_TODOS,
  openChat,
  reuseThreadChatEntry,
  skipIfMissingThread,
  waitForMessageListReady,
} from "./support/chat-helpers";

async function waitForAnyMessages(
  page: Parameters<typeof openChat>[0],
  timeoutMs = 15_000,
) {
  const deadline = Date.now() + timeoutMs;
  while (Date.now() < deadline) {
    const count = await page.locator(".is-user, .is-assistant").count();
    if (count > 0) {
      return count;
    }
    await page.waitForTimeout(300);
  }
  return 0;
}

test.describe("聊天工作台 / 消息区与历史", () => {
  test("DF-MSG-001 固定 fixture 历史消息可见", async ({ page }, testInfo) => {
    skipIfMissingThread(
      testInfo,
      THREAD_WITH_HISTORY,
      "FRONTEND_E2E_THREAD_ID",
    );
    await openChat(page, reuseThreadChatEntry(THREAD_WITH_HISTORY!));
    await waitForMessageListReady(page, { requireMessages: false });
    const messageCount = await waitForAnyMessages(page);
    testInfo.skip(messageCount === 0, "当前历史线程没有可见消息。");

    await expect(page.locator(".is-user, .is-assistant").first()).toBeVisible();
  });

  test("DF-MSG-002 Markdown 消息结构可见", async ({ page }, testInfo) => {
    skipIfMissingThread(
      testInfo,
      THREAD_WITH_MARKDOWN,
      "FRONTEND_E2E_MARKDOWN_THREAD_ID",
    );
    await openChat(page, reuseThreadChatEntry(THREAD_WITH_MARKDOWN!));
    await waitForMessageListReady(page, { requireMessages: false });

    const messageCount = await waitForAnyMessages(page);
    testInfo.skip(
      messageCount === 0,
      "当前线程没有可用于断言 Markdown 结构的历史消息。",
    );

    const markdownCandidates = page.locator(
      ".is-assistant strong, .is-assistant ul li, .is-assistant ol li, .is-assistant code",
    );
    await expect(markdownCandidates.first()).toBeVisible();
  });

  test("DF-MSG-003 长历史线程中可出现滚动到底部按钮", async ({
    page,
  }, testInfo) => {
    skipIfMissingThread(
      testInfo,
      THREAD_WITH_HISTORY,
      "FRONTEND_E2E_THREAD_ID",
    );
    await openChat(page, reuseThreadChatEntry(THREAD_WITH_HISTORY!));
    await waitForMessageListReady(page, { requireMessages: false });
    const messageCount = await waitForAnyMessages(page);
    testInfo.skip(messageCount === 0, "当前历史线程没有可见消息。");

    const messageLog = page.getByRole("log").first();
    const canScroll = await messageLog.evaluate((element) => {
      const target = element as HTMLElement;
      return target.scrollHeight - target.clientHeight > 20;
    });
    testInfo.skip(
      canScroll === false,
      "当前线程消息区高度不足，无法触发滚动到底部按钮。",
    );

    await messageLog.hover();
    await page.mouse.wheel(0, -1200);
    await messageLog.evaluate((element) => {
      const target = element as HTMLElement;
      target.scrollTop = Math.max(0, target.scrollTop - 1200);
    });

    await expect(page.getByTitle("滚动到底部")).toBeVisible();
  });

  test("DF-MSG-004 刷新前后用户消息关键内容保持一致", async ({
    page,
  }, testInfo) => {
    skipIfMissingThread(
      testInfo,
      THREAD_WITH_HISTORY,
      "FRONTEND_E2E_THREAD_ID",
    );
    await openChat(page, reuseThreadChatEntry(THREAD_WITH_HISTORY!));
    await waitForMessageListReady(page, { requireMessages: false });

    const normalizeText = (text: string) => text.replace(/\s+/g, " ").trim();
    const beforeUsers = (await page.locator(".is-user").allTextContents())
      .map(normalizeText)
      .filter(Boolean);

    testInfo.skip(beforeUsers.length === 0, "当前历史线程没有可见用户消息。");

    await page.reload();
    await expect(page.locator("textarea[name='message']")).toBeVisible();
    await waitForMessageListReady(page, { requireMessages: false });

    const afterUsers = (await page.locator(".is-user").allTextContents())
      .map(normalizeText)
      .filter(Boolean);

    expect(afterUsers.length).toBe(beforeUsers.length);
    for (const sample of beforeUsers.slice(
      0,
      Math.min(3, beforeUsers.length),
    )) {
      expect(afterUsers.some((text) => text.includes(sample))).toBeTruthy();
    }
  });

  test("DF-MSG-005 含 todos 的线程显示 To-dos 入口", async ({
    page,
  }, testInfo) => {
    skipIfMissingThread(
      testInfo,
      THREAD_WITH_TODOS,
      "FRONTEND_E2E_TODOS_THREAD_ID",
    );
    await openChat(page, reuseThreadChatEntry(THREAD_WITH_TODOS!));
    await waitForMessageListReady(page, { requireMessages: false });

    const todoButton = page.getByRole("button", { name: /To-dos/i });
    testInfo.skip(
      (await todoButton.count()) === 0,
      "当前线程未展示 To-dos 入口。",
    );
    await expect(todoButton).toBeVisible();
  });
});
