#!/usr/bin/env node
"use strict";

const fs = require("node:fs");
const os = require("node:os");
const path = require("node:path");
const { chromium } = require("playwright");

const OUTPUT_DIR = path.resolve(__dirname, "..", "tmp", "task490-runtime-surfaces-smoke");
const TASK = "task490-runtime-surfaces-smoke";
const TARGET_BLOCK_ID = "task490-runtime-surface-target";

function screenshotPath(name) {
  fs.mkdirSync(OUTPUT_DIR, { recursive: true });
  return path.join(OUTPUT_DIR, `${name}.png`);
}

function fileUrl(localPath) {
  return `file://${localPath}`;
}

function localMdDocumentId(relativePath) {
  return `local-md:${relativePath.replaceAll("/", "~2F")}`;
}

function documentUrl(baseUrl, root, relativePath) {
  const url = new URL(`${baseUrl}/documents/${encodeURIComponent(localMdDocumentId(relativePath))}`);
  url.searchParams.set("sourceKind", "local_folder");
  url.searchParams.set("rootUri", fileUrl(root));
  url.searchParams.set("treeView", "filetree");
  return url.toString();
}

function writeWorkspaceManifest(root, ownerId) {
  const metadataDir = path.join(root, ".mnote");
  fs.mkdirSync(metadataDir, { recursive: true });
  fs.writeFileSync(
    path.join(metadataDir, "workspace.json"),
    `${JSON.stringify({
      workspaceId: `local-ws:${ownerId}:task490`,
      ownerId,
      createdAt: new Date().toISOString(),
      capabilities: ["local_files", "markdown_edit", "asset_upload"],
    }, null, 2)}\n`,
    "utf8",
  );
}

async function saveScreenshot(page, name) {
  const target = screenshotPath(name);
  await page.screenshot({ path: target, fullPage: false });
  return target;
}

async function waitForRuntimeIsland(page, uiTimeoutMs) {
  const root = page.locator('[data-testid="mnote-leptos-tiptap-island-editor-root"]').first();
  await root.waitFor({ state: "visible", timeout: uiTimeoutMs });
  const editor = page
    .locator('[data-testid="mnote-leptos-tiptap-island-editor-root"] .editor-surface .ProseMirror[contenteditable="true"]')
    .first();
  await editor.waitFor({ state: "visible", timeout: uiTimeoutMs });
  await page.waitForFunction(
    () => {
      const host = document.querySelector('[data-testid="mnote-leptos-tiptap-island-editor-root"]');
      const editorNode = host?.querySelector('.editor-surface .ProseMirror[contenteditable="true"]');
      return host?.getAttribute("data-runtime-editor-status") !== "error"
        && editorNode instanceof HTMLElement
        && editorNode.isContentEditable;
    },
    null,
    { timeout: uiTimeoutMs },
  );
  return editor;
}

async function setBlockHandleFixture(page, uiTimeoutMs) {
  await page.evaluate((targetBlockId) => {
    const editor = document.querySelector(".editor-surface .ProseMirror")?.editor;
    if (!editor) {
      throw new Error("找不到 Tiptap editor");
    }
    editor.commands.setContent(
      {
        type: "doc",
        content: [
          {
            type: "paragraph",
            attrs: { blockId: targetBlockId },
            content: [{ type: "text", text: "Task490 block handle target" }],
          },
          {
            type: "paragraph",
            attrs: { blockId: "task490-second-block" },
            content: [{ type: "text", text: "Task490 slash target" }],
          },
        ],
      },
      true,
    );
    editor.commands.focus("end");
  }, TARGET_BLOCK_ID);

  await page.waitForFunction(
    (targetBlockId) => document.querySelector(`[data-block-id="${targetBlockId}"]`) instanceof HTMLElement,
    TARGET_BLOCK_ID,
    { timeout: uiTimeoutMs },
  );
}

async function closePageAiIfOpen(page) {
  const closeButton = page.locator('[data-page-ai-action="close"]').first();
  if (await closeButton.isVisible().catch(() => false)) {
    await closeButton.click().catch(() => undefined);
  }
}

async function main() {
  fs.mkdirSync(OUTPUT_DIR, { recursive: true });
  delete require.cache[require.resolve("./tree-shell-smoke-helpers")];
  const {
    BASE_URL,
    UI_TIMEOUT_MS,
    assert,
    ensureAuthenticated,
  } = require("./tree-shell-smoke-helpers");

  const browser = await chromium.launch({ headless: true });
  const context = await browser.newContext({
    viewport: { width: 1440, height: 960 },
    locale: "zh-CN",
    extraHTTPHeaders: {
      "x-mnote-actor-id": "mnote-e2e",
      "x-mnote-actor-type": "user",
    },
  });
  const page = await context.newPage();
  const screenshots = {};
  const root = fs.mkdtempSync(path.join(os.tmpdir(), "mnote-task490-"));
  const relativePath = "RuntimeSurfaces.md";
  writeWorkspaceManifest(root, "mnote-e2e");
  fs.writeFileSync(
    path.join(root, relativePath),
    ["# Runtime Surfaces", "", "Task490 initial paragraph", ""].join("\n"),
    "utf8",
  );
  let caughtError = null;

  try {
    await ensureAuthenticated(page, context.request);

    const url = documentUrl(BASE_URL, root, relativePath);
    const response = await page.goto(url, { waitUntil: "domcontentloaded", timeout: UI_TIMEOUT_MS });
    assert(response, "文档页没有返回响应");
    assert(response.status() === 200, `文档页状态码异常: ${response.status()}`);
    const editor = await waitForRuntimeIsland(page, UI_TIMEOUT_MS);
    await setBlockHandleFixture(page, UI_TIMEOUT_MS);

    const moreButton = page.locator('[data-testid="wolai-page-settings-trigger"]').first();
    await moreButton.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
    await moreButton.click({ timeout: UI_TIMEOUT_MS });
    const settingsPopover = page.locator('[data-testid="wolai-page-settings-popover"]').first();
    await settingsPopover.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
    const settingsText = (await settingsPopover.textContent()) || "";
    assert(settingsText.includes("页面选项"), `页面设置 popover 未显示页面选项: ${settingsText}`);
    screenshots.pageSettings = await saveScreenshot(page, "01-page-settings");
    await page.keyboard.press("Escape").catch(() => undefined);

    const aiButton = page.locator('[data-testid="wolai-floating-ai"]').first();
    await aiButton.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
    await aiButton.click({ timeout: UI_TIMEOUT_MS });
    const aiDrawer = page.locator('[data-testid="wolai-page-ai-drawer"]').first();
    await aiDrawer.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
    const aiText = (await aiDrawer.textContent()) || "";
    assert(aiText.includes("Hermes"), `Page AI drawer 必须显示 Hermes 入口: ${aiText}`);
    assert(await page.locator("[data-page-ai-input]").first().isVisible(), "Page AI drawer 必须显示输入框");
    screenshots.pageAi = await saveScreenshot(page, "02-page-ai");
    await closePageAiIfOpen(page);

    await editor.click({ timeout: UI_TIMEOUT_MS });
    await page.keyboard.type("/");
    const slashMenu = page.locator('[data-testid="mnote-leptos-tiptap-slash-menu"]').first();
    await slashMenu.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
    const slashText = (await slashMenu.textContent()) || "";
    assert(slashText.trim().length > 0, "slash menu 必须显示可选项");
    screenshots.slashMenu = await saveScreenshot(page, "03-slash-menu");
    await page.keyboard.press("Escape");

    const target = page.locator(`[data-block-id="${TARGET_BLOCK_ID}"]`).first();
    await target.scrollIntoViewIfNeeded({ timeout: UI_TIMEOUT_MS });
    const targetBox = await target.boundingBox();
    assert(targetBox, "block handle 目标块缺少可测量区域");
    await page.mouse.move(targetBox.x + 8, targetBox.y + Math.min(12, Math.max(4, targetBox.height / 2)));
    const blockHandle = page.locator('[data-testid="block-drag-handle-trigger"]').first();
    await blockHandle.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
    await blockHandle.click({ timeout: UI_TIMEOUT_MS });
    const blockMenu = page.locator('[data-testid="block-drag-menu"]').first();
    await blockMenu.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
    const blockMenuText = (await blockMenu.textContent()) || "";
    assert(blockMenuText.includes("删除") || blockMenuText.includes("Delete"), `block handle menu 缺少基础操作: ${blockMenuText}`);
    screenshots.blockHandleMenu = await saveScreenshot(page, "04-block-handle-menu");

    const result = {
      ok: true,
      task: TASK,
      baseUrl: BASE_URL,
      root,
      relativePath,
      documentId: localMdDocumentId(relativePath),
      screenshotDir: OUTPUT_DIR,
      screenshots,
    };
    fs.writeFileSync(path.join(OUTPUT_DIR, "result.json"), `${JSON.stringify(result, null, 2)}\n`, "utf8");
    console.log(JSON.stringify(result, null, 2));
  } catch (error) {
    caughtError = error;
    await saveScreenshot(page, "failure").catch(() => undefined);
  } finally {
    fs.rmSync(root, { recursive: true, force: true });
    await page.close().catch(() => undefined);
    await context.close().catch(() => undefined);
    await browser.close().catch(() => undefined);
  }

  if (caughtError) {
    throw caughtError;
  }
}

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