"use strict";

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

async function waitForPageTitleInput(page) {
  const input = page.getByLabel("页面标题");
  await input.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
  return input;
}

async function waitForTitleSave(page, documentId, expectedTitle) {
  await page.waitForResponse(
    async (response) => {
      if (!response.url().includes("/api/documents/title") || response.request().method() !== "POST") {
        return false;
      }
      const payload = response.request().postDataJSON();
      return payload?.documentId === documentId && payload?.title === expectedTitle && response.ok();
    },
    { timeout: UI_TIMEOUT_MS },
  );
}

async function renameThroughPageHead(page, documentId, title) {
  const titleInput = await waitForPageTitleInput(page);
  await titleInput.click({ timeout: UI_TIMEOUT_MS });
  await page.keyboard.press("Control+a");
  await page.keyboard.type(title, { delay: 20 });
  await titleInput.blur();
  await waitForTitleSave(page, documentId, title);
}

async function waitForBreadcrumbTitle(page, title) {
  await page.waitForFunction(
    (expectedTitle) => {
      const nav = document.querySelector("header nav");
      return (nav?.textContent ?? "").includes(expectedTitle);
    },
    title,
    { timeout: UI_TIMEOUT_MS },
  );
}

async function waitForSidebarRowTitle(page, documentId, title) {
  await page.waitForFunction(
    ({ docId, expectedTitle }) => {
      const row = document.querySelector(`aside a[href="/documents/${docId}"]`);
      return (row?.textContent ?? "").includes(expectedTitle);
    },
    { docId: documentId, expectedTitle: title },
    { timeout: UI_TIMEOUT_MS },
  );
}

async function waitForPageTreeTitle(page, documentId, title) {
  await openSectionView(page);
  const shellHost = page.getByTestId("sidebar-page-tree-shell");
  await shellHost.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
  await page.waitForFunction(
    ({ nodeId, expectedTitle }) => {
      const row = document.querySelector(
        `[data-testid="page-tree-row"][data-node-id="${nodeId}"]`,
      );
      return (row?.textContent ?? "").includes(expectedTitle);
    },
    { nodeId: documentId, expectedTitle: title },
    { timeout: UI_TIMEOUT_MS },
  );
}

async function waitForFileTreeTitle(page, documentId, title) {
  await openFilesystemView(page);
  const shellHost = page.getByTestId("sidebar-file-tree-shell");
  await shellHost.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
  await page.waitForFunction(
    ({ docId, expectedTitle }) => {
      const row = document.querySelector(
        `[data-testid="filetree-doc-row"][data-doc-id="${docId}"]`,
      );
      return (row?.textContent ?? "").includes(expectedTitle);
    },
    { docId: documentId, expectedTitle: title },
    { timeout: UI_TIMEOUT_MS },
  );
}

async function readVisibleTitle(page) {
  const titleInput = page.getByLabel("页面标题");
  if (await titleInput.isVisible().catch(() => false)) {
    return (await titleInput.inputValue()).trim();
  }
  const heading = page.locator("h1").first();
  return ((await heading.textContent()) ?? "").trim();
}

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 fixture = null;

  try {
    const viewer = await ensureAuthenticated(page, context.request);
    const first = await createTempDocument(context.request, null);
    const second = await createTempDocument(context.request, null);
    const initialTitle = `phase-i-initial-${Date.now().toString().slice(-6)}`;
    const renamedTitle = `phase-i-renamed-${(Date.now() + 1).toString().slice(-6)}`;
    const siblingTitle = `phase-i-sibling-${(Date.now() + 2).toString().slice(-6)}`;

    await renameDocument(context.request, first.workspaceId, first.documentId, initialTitle);
    await renameDocument(context.request, second.workspaceId, second.documentId, siblingTitle);

    fixture = {
      workspaceId: first.workspaceId,
      primaryId: first.documentId,
      siblingId: second.documentId,
      createdIds: [first.documentId, second.documentId],
      initialTitle,
      renamedTitle,
      siblingTitle,
    };

    await openDocument(page, fixture.workspaceId, fixture.primaryId);
    await waitForPageTitleInput(page);
    assert((await readVisibleTitle(page)).includes(initialTitle), "页头未回填初始标题");

    await renameThroughPageHead(page, fixture.primaryId, fixture.renamedTitle);
    assert((await readVisibleTitle(page)).includes(fixture.renamedTitle), "页头未显示最新标题");

    await waitForBreadcrumbTitle(page, fixture.renamedTitle);
    await waitForSidebarRowTitle(page, fixture.primaryId, fixture.renamedTitle);
    await waitForPageTreeTitle(page, fixture.primaryId, fixture.renamedTitle);
    await waitForFileTreeTitle(page, fixture.primaryId, fixture.renamedTitle);

    await openDocument(page, fixture.workspaceId, fixture.siblingId);
    await waitForPageTitleInput(page);
    assert((await readVisibleTitle(page)).includes(fixture.siblingTitle), "切到兄弟页后标题不正确");

    await openDocument(page, fixture.workspaceId, fixture.primaryId);
    await waitForPageTitleInput(page);
    await waitForBreadcrumbTitle(page, fixture.renamedTitle);
    await waitForSidebarRowTitle(page, fixture.primaryId, fixture.renamedTitle);
    assert((await readVisibleTitle(page)).includes(fixture.renamedTitle), "切页往返后页头标题回闪");

    await page.reload({ waitUntil: "commit", timeout: UI_TIMEOUT_MS });
    await waitForPageTitleInput(page);
    await waitForBreadcrumbTitle(page, fixture.renamedTitle);
    await waitForSidebarRowTitle(page, fixture.primaryId, fixture.renamedTitle);
    await waitForPageTreeTitle(page, fixture.primaryId, fixture.renamedTitle);
    await waitForFileTreeTitle(page, fixture.primaryId, fixture.renamedTitle);
    assert((await readVisibleTitle(page)).includes(fixture.renamedTitle), "刷新后页头标题未保持一致");

    console.log(
      JSON.stringify(
        {
          ok: true,
          baseUrl: BASE_URL,
          viewerUserId: viewer.userId,
          workspaceId: fixture.workspaceId,
          primaryId: fixture.primaryId,
          siblingId: fixture.siblingId,
          renamedTitle: fixture.renamedTitle,
        },
        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);
});
