"use strict";

const { chromium } = require("playwright");
const {
  BASE_URL,
  UI_TIMEOUT_MS,
  assert,
  cleanupDocuments,
  ensureAuthenticated,
  openDocument,
  openSectionView,
  prepareTempTreeFixture,
} = require("./tree-shell-smoke-helpers");

async function runPrimaryPath(page, fixture) {
  const streamRequestPromise = page.waitForRequest(
    (request) =>
      request.url().includes("/api/stream/events") &&
      request.method() === "GET",
    { timeout: UI_TIMEOUT_MS },
  );

  await openDocument(page, fixture.workspaceId, fixture.parentId);
  await openSectionView(page);
  const streamRequest = await streamRequestPromise;

  const shellHost = page.getByTestId("sidebar-page-tree-shell");
  const firstVisibleStart = Date.now();
  await shellHost.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
  const parentRow = shellHost.locator(`[data-testid="page-tree-row"][data-node-id="${fixture.parentId}"]`);
  const childRow = shellHost.locator(`[data-testid="page-tree-row"][data-node-id="${fixture.childId}"]`);
  await parentRow.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
  await childRow.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
  const firstVisibleMs = Date.now() - firstVisibleStart;

  assert(
    (await shellHost.locator('iframe[title="mnote-web tree shell"]').count()) === 0,
    "Sidebar 主树仍残留 iframe tree shell",
  );

  const navigateStart = Date.now();
  await childRow.getByTestId("page-tree-open").click({ timeout: UI_TIMEOUT_MS });
  await page.waitForURL((url) => url.toString().includes(`/documents/${fixture.childId}`), {
    timeout: UI_TIMEOUT_MS,
  });
  const navigateMs = Date.now() - navigateStart;

  return {
    streamUrl: streamRequest.url(),
    firstVisibleMs,
    navigateMs,
  };
}

async function runFallbackPath(context, fixture) {
  const page = await context.newPage();
  let blockedCount = 0;
  await page.route("**/api/stream/events**", async (route) => {
    blockedCount += 1;
    await route.abort("failed");
  });

  try {
    await openDocument(page, fixture.workspaceId, fixture.parentId);
    await openSectionView(page);

    const shellHost = page.getByTestId("sidebar-page-tree-shell");
    const fallbackStart = Date.now();
    await shellHost.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
    await shellHost.locator(`[data-testid="page-tree-row"][data-node-id="${fixture.parentId}"]`).waitFor({
      state: "visible",
      timeout: UI_TIMEOUT_MS,
    });
    await shellHost.locator(`[data-testid="page-tree-row"][data-node-id="${fixture.childId}"]`).waitFor({
      state: "visible",
      timeout: UI_TIMEOUT_MS,
    });
    const fallbackVisibleMs = Date.now() - fallbackStart;

    assert(blockedCount > 0, "未命中 stream fallback 拦截");
    assert(
      (await shellHost.locator('iframe[title="mnote-web tree shell"]').count()) === 0,
      "fallback 路径仍残留 iframe tree shell",
    );

    return {
      blockedCount,
      fallbackVisibleMs,
    };
  } finally {
    await page.close().catch(() => undefined);
  }
}

async function main() {
  const browser = await chromium.launch({ headless: true });
  const context = await browser.newContext({
    viewport: { width: 1440, height: 960 },
  });
  const page = await context.newPage();

  let caughtError = null;
  let result = null;
  let fixture = null;

  try {
    const viewer = await ensureAuthenticated(page, context.request);
    fixture = await prepareTempTreeFixture(context.request);

    const primary = await runPrimaryPath(page, fixture);
    const fallback = await runFallbackPath(context, fixture);

    result = {
      ok: true,
      baseUrl: BASE_URL,
      viewerUserId: viewer.userId,
      workspaceId: fixture.workspaceId,
      parentId: fixture.parentId,
      childId: fixture.childId,
      primary,
      fallback,
    };

    console.log(JSON.stringify(result, null, 2));
  } catch (error) {
    caughtError = error;
  } finally {
    if (fixture) {
      try {
        await cleanupDocuments(context.request, fixture.createdIds);
      } catch (cleanupError) {
        if (!caughtError) {
          caughtError = cleanupError;
        } else {
          console.error(
            `清理临时页面失败：${
              cleanupError instanceof Error
                ? cleanupError.stack || cleanupError.message
                : String(cleanupError)
            }`,
          );
        }
      }
    }
    await page.close().catch(() => undefined);
    await context.close().catch(() => undefined);
    await browser.close().catch(() => undefined);
  }

  if (caughtError) {
    throw caughtError;
  }
}

main().catch((error) => {
  console.error(error instanceof Error ? error.stack || error.message : String(error));
  process.exit(1);
});
