"use strict";

// 说明：
// - 这份 smoke 只验证 rust_family picker 的键盘高亮与 Enter 选中。
// - 这里刻意使用 fresh-open 的最短链路，避免把空态/多轮搜索切换的抖动混进同一条回归里。

const { chromium } = require("playwright");
const {
  UI_TIMEOUT_MS,
  createTempDocument,
  ensureAuthenticated,
  ensurePageOptionsVisible,
  openDocument,
  purgeDocument,
  renameDocument,
} = require("./tree-shell-smoke-helpers");

const ALLOW_LEGACY_TREE_SHELL_IFRAME_HOST =
  String(process.env.NEXT_PUBLIC_TREE_SHELL_LEGACY_IFRAME_HOST || "").trim() === "1";

function treeHostImplementationUsesIframe(implementation) {
  return (
    implementation === "mnote_web_iframe_proxy" ||
    implementation === "rust_inline_compat_host" ||
    implementation === "rust_runtime_artifact_host"
  );
}

async function waitForPickerShellReady(page) {
  await page.waitForFunction(
    () => {
      const host = document.querySelector('[data-testid="tree-picker-surface"]');
      if (!(host instanceof HTMLElement) || host.getClientRects().length === 0) {
        return false;
      }
      const implementation = host.getAttribute("data-tree-host-implementation") || "";
      if (
        implementation === "mnote_web_iframe_proxy" ||
        implementation === "rust_inline_compat_host" ||
        implementation === "rust_runtime_artifact_host"
      ) {
        const iframe = host.querySelector('[data-testid="tree-picker-surface-rust-iframe"]');
        if (!(iframe instanceof HTMLIFrameElement) || iframe.getClientRects().length === 0) {
          return false;
        }
        const doc = iframe.contentDocument;
        const status = doc?.querySelector("#tree-shell-status")?.textContent ?? "";
        return Boolean(doc?.querySelector("#tree-shell-state")) && status.includes("就绪");
      }
      const domHost = host.querySelector('[data-testid="tree-picker-surface-dom-host"]');
      return (
        domHost instanceof HTMLElement &&
        domHost.getClientRects().length > 0 &&
        domHost.getAttribute("data-tree-browser-bridge") === "dom_wasm" &&
        domHost.getAttribute("data-tree-dom-shell-ready") === "true"
      );
    },
    undefined,
    { timeout: UI_TIMEOUT_MS },
  );
}

async function pickerUsesLegacyIframe(pickerSurface) {
  const implementation = await pickerSurface.getAttribute("data-tree-host-implementation");
  if (treeHostImplementationUsesIframe(implementation) && !ALLOW_LEGACY_TREE_SHELL_IFRAME_HOST) {
    throw new Error(
      `tree-picker-surface 默认主路径不能再使用 legacy iframe host: ${implementation || "unknown"}`,
    );
  }
  return (
    treeHostImplementationUsesIframe(implementation) &&
    (await pickerSurface.locator('[data-testid="tree-picker-surface-rust-iframe"]').count()) > 0
  );
}

async function main() {
  const headless =
    process.env.MNOTE_SMOKE_HEADLESS === "1"
      ? true
      : process.env.MNOTE_SMOKE_HEADLESS === "0"
        ? false
        : !process.env.DISPLAY;
  const browser = await chromium.launch({ headless });
  const context = await browser.newContext({
    viewport: { width: 1440, height: 960 },
  });
  const page = await context.newPage();

  let fixture = null;
  let caughtError = null;

  try {
    await ensureAuthenticated(page, context.request);
    const uniqueSuffix = Date.now().toString();
    const parent = await createTempDocument(context.request, null);
    const childA = await createTempDocument(context.request, parent.documentId);
    const target = await createTempDocument(context.request, null);

    fixture = {
      workspaceId: parent.workspaceId,
      parentId: parent.documentId,
      childAId: childA.documentId,
      targetId: target.documentId,
      parentTitle: `task113-parent-${uniqueSuffix}`,
      childATitle: `task113-child-a-${uniqueSuffix}`,
      targetTitle: `task113-target-${uniqueSuffix}`,
      createdIds: [parent.documentId, childA.documentId, target.documentId],
    };

    await renameDocument(context.request, fixture.workspaceId, fixture.parentId, fixture.parentTitle);
    await renameDocument(context.request, fixture.workspaceId, fixture.childAId, fixture.childATitle);
    await renameDocument(context.request, fixture.workspaceId, fixture.targetId, fixture.targetTitle);

    await openDocument(page, fixture.workspaceId, fixture.childAId);
    await ensurePageOptionsVisible(page);
    const openButton = page.getByRole("button", { name: "移动/嵌入到..." });
    await openButton.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
    await openButton.click({ timeout: UI_TIMEOUT_MS });

    const dialog = page.getByRole("dialog");
    await dialog.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
    const pickerSurface = dialog.getByTestId("tree-picker-surface");
    await pickerSurface.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
    await waitForPickerShellReady(page);
    const usesLegacyIframe = await pickerUsesLegacyIframe(pickerSurface);
    const searchInput = dialog.getByPlaceholder("移动到...");
    const keyboardQuery = `task113-keyboard-${Date.now()}`;

    await page.route("**/api/search/documents", async (route) => {
      const payload = route.request().postDataJSON();
      if (payload?.query !== keyboardQuery) {
        await route.continue();
        return;
      }
      await route.fulfill({
        status: 200,
        contentType: "application/json",
        body: JSON.stringify({
          results: [
            {
              id: fixture.parentId,
              title: fixture.parentTitle,
              matchField: "title",
            },
            {
              id: fixture.targetId,
              title: fixture.targetTitle,
              matchField: "title",
            },
          ],
        }),
      });
    });

    try {
      await searchInput.fill(keyboardQuery, { timeout: UI_TIMEOUT_MS });
      if (usesLegacyIframe) {
        await page.waitForFunction(
          (nodeId) => {
            const frame = Array.from(
              document.querySelectorAll('[data-testid="tree-picker-surface-rust-iframe"]'),
            )
              .reverse()
              .find((element) => element instanceof HTMLIFrameElement) ?? null;
            if (!(frame instanceof HTMLIFrameElement)) {
              return false;
            }
            return Boolean(frame.contentDocument?.querySelector(`.tree-row[data-node-id="${nodeId}"]`));
          },
          fixture.targetId,
          { timeout: UI_TIMEOUT_MS },
        );
      } else {
        await dialog
          .locator(`[data-testid="tree-picker-row"][data-node-id="${fixture.targetId}"]`)
          .waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
      }

      await searchInput.focus();
      await page.waitForFunction(
        () => {
          const active = document.activeElement;
          return active instanceof HTMLInputElement && active.placeholder === "移动到...";
        },
        undefined,
        { timeout: UI_TIMEOUT_MS },
      );

      const readFocusedPickerItemKey = async () =>
        usesLegacyIframe
          ? page.evaluate(() => {
              const frame = Array.from(
                document.querySelectorAll('[data-testid="tree-picker-surface-rust-iframe"]'),
              )
                .reverse()
                .find((element) => element instanceof HTMLIFrameElement) ?? null;
              if (!(frame instanceof HTMLIFrameElement) || !frame.contentDocument) {
                return "";
              }
              const rootButton = frame.contentDocument.querySelector(
                '[data-testid="tree-picker-root"][data-focused="true"]',
              );
              if (rootButton) {
                return "__root__";
              }
              const row = frame.contentDocument.querySelector('.tree-row[data-focused="true"]');
              return row ? row.getAttribute("data-node-id") || "" : "";
            })
          : dialog.evaluate((dialogElement) => {
              const rootButton = dialogElement.querySelector('[data-testid="tree-picker-root"][data-focused="true"]');
              if (rootButton) {
                return "__root__";
              }
              const row = dialogElement.querySelector('.tree-row[data-focused="true"]');
              return row ? row.getAttribute("data-node-id") || "" : "";
            });

      const moveHighlightTo = async (targetNodeId, maxSteps = 4) => {
        if (usesLegacyIframe) {
          await page.waitForFunction(
            () => {
              const frame = Array.from(
                document.querySelectorAll('[data-testid="tree-picker-surface-rust-iframe"]'),
              )
                .reverse()
                .find((element) => element instanceof HTMLIFrameElement) ?? null;
              if (!(frame instanceof HTMLIFrameElement) || !frame.contentDocument) {
                return false;
              }
              const rootButton = frame.contentDocument.querySelector(
                '[data-testid="tree-picker-root"][data-focused="true"]',
              );
              const row = frame.contentDocument.querySelector('.tree-row[data-focused="true"]');
              return Boolean(rootButton || row);
            },
            undefined,
            { timeout: UI_TIMEOUT_MS },
          );
        } else {
          await dialog
            .locator('[data-testid="tree-picker-root"][data-focused="true"], .tree-row[data-focused="true"]')
            .first()
            .waitFor({ state: "attached", timeout: UI_TIMEOUT_MS });
        }

        for (let index = 0; index < maxSteps; index += 1) {
          const currentKey = await readFocusedPickerItemKey();
          if (currentKey === targetNodeId) {
            return;
          }
          await page.keyboard.press("ArrowDown");
          await page.waitForFunction(
            ({ previousKey, legacyIframe }) => {
              if (legacyIframe) {
                const frame = Array.from(
                  document.querySelectorAll('[data-testid="tree-picker-surface-rust-iframe"]'),
                )
                  .reverse()
                  .find((element) => element instanceof HTMLIFrameElement) ?? null;
                if (!(frame instanceof HTMLIFrameElement) || !frame.contentDocument) {
                  return false;
                }
                const rootButton = frame.contentDocument.querySelector(
                  '[data-testid="tree-picker-root"][data-focused="true"]',
                );
                const row = frame.contentDocument.querySelector('.tree-row[data-focused="true"]');
                const currentKey = rootButton
                  ? "__root__"
                  : row
                    ? row.getAttribute("data-node-id") || ""
                    : "";
                return currentKey !== previousKey;
              }
              const dialogElement = document.querySelector('[role="dialog"]');
              if (!(dialogElement instanceof HTMLElement)) {
                return false;
              }
              const rootButton = dialogElement.querySelector('[data-testid="tree-picker-root"][data-focused="true"]');
              const row = dialogElement.querySelector('.tree-row[data-focused="true"]');
              const currentKey = rootButton
                ? "__root__"
                : row
                  ? row.getAttribute("data-node-id") || ""
                  : "";
              return currentKey !== previousKey;
            },
            { previousKey: currentKey, legacyIframe: usesLegacyIframe },
            { timeout: UI_TIMEOUT_MS },
          );
          await page.waitForFunction(
            () => {
              const active = document.activeElement;
              return active instanceof HTMLInputElement && active.placeholder === "移动到...";
            },
            undefined,
            { timeout: UI_TIMEOUT_MS },
          );
        }

        const finalKey = await readFocusedPickerItemKey();
        if (finalKey !== targetNodeId) {
          throw new Error(`picker 键盘高亮未落到目标节点：当前=${finalKey || "<empty>"} 目标=${targetNodeId}`);
        }
      };

      await moveHighlightTo(fixture.targetId);

      const moveRequest = page.waitForResponse(
        async (response) => {
          if (
            !response.url().includes("/api/tree/commands") ||
            response.request().method() !== "POST" ||
            !response.ok()
          ) {
            return false;
          }
          const payload = response.request().postDataJSON();
          return payload?.action === "move" && payload?.documentId === fixture.childAId && payload?.parentId === fixture.targetId;
        },
        { timeout: UI_TIMEOUT_MS },
      );

      await searchInput.focus();
      await page.keyboard.press("Enter");
      await moveRequest;
      await dialog.waitFor({ state: "hidden", timeout: UI_TIMEOUT_MS });
    } finally {
      await page.unroute("**/api/search/documents").catch(() => undefined);
    }

    console.log(
      JSON.stringify(
        {
          ok: true,
          workspaceId: fixture.workspaceId,
          sourceId: fixture.childAId,
          targetId: fixture.targetId,
          searchQuery: keyboardQuery,
          pickerKeyboardHighlight: true,
          pickerKeyboardSelect: true,
        },
        null,
        2,
      ),
    );
  } catch (error) {
    caughtError = error;
  } finally {
    if (fixture) {
      for (const documentId of [...fixture.createdIds].reverse()) {
        try {
          await purgeDocument(context.request, documentId);
        } catch {
          // 说明：移动后父级与目标级的清理顺序可能变化，这里忽略重复清理错误。
        }
      }
    }

    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);
});
