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

const fs = require("node:fs/promises");
const path = require("node:path");
const { chromium } = require("playwright");
const {
  BASE_URL,
  UI_TIMEOUT_MS,
  cleanupDocuments,
  createTempDocument,
  ensureAuthenticated,
  renameDocument,
} = require("./tree-shell-smoke-helpers");

const TASK = "task179-tree-create-delete-no-reload-smoke";
const OUTPUT_DIR = path.join(process.cwd(), "tmp", TASK);
const RESULT_PATH = path.join(OUTPUT_DIR, "result.json");

if (process.env.MNOTE_ALLOW_DEBUG_TREE_SMOKE !== "1") {
  console.log(
    JSON.stringify(
      {
        ok: true,
        skipped: true,
        task: TASK,
        reason:
          "task179 只覆盖已退为显式 debug/internal 的 /tree 壳；默认跳过，避免干扰 local-first 主链回归。设置 MNOTE_ALLOW_DEBUG_TREE_SMOKE=1 后可显式复核。",
      },
      null,
      2,
    ),
  );
  process.exit(0);
}

async function writeResult(payload) {
  await fs.mkdir(OUTPUT_DIR, { recursive: true });
  await fs.writeFile(RESULT_PATH, `${JSON.stringify({ ...payload, resultPath: RESULT_PATH }, null, 2)}\n`, "utf8");
}

function fileTreeDocumentRowSelector(documentId) {
  return `[data-testid="filetree-doc-row"][data-document-id="${documentId}"], [data-testid="filetree-doc-row"][data-doc-id="${documentId}"]`;
}

function pageTreeDocumentRowSelector(documentId) {
  return `.tree-row[data-shell-mode="page"][data-node-id="${documentId}"]`;
}

function documentRowSelector(mode, documentId) {
  return mode === "page" ? pageTreeDocumentRowSelector(documentId) : fileTreeDocumentRowSelector(documentId);
}

function renameInputSelector(mode) {
  return mode === "page"
    ? ".tree-rename-input[data-rename-id]"
    : ".tree-rename-input[data-rename-id^='doc:']";
}

function documentIdFromRenameId(mode, renameId) {
  return mode === "page" ? String(renameId || "") : String(renameId || "").replace(/^doc:/, "");
}

async function readShellState(page) {
  return page.evaluate(() => ({
    url: window.location.href,
    rows: Array.from(document.querySelectorAll(".tree-row[data-shell-mode='filetree']")).map((row) => ({
      rowId: row instanceof HTMLElement ? row.dataset.rowId || "" : "",
      documentId: row instanceof HTMLElement ? row.dataset.documentId || "" : "",
      title: row instanceof HTMLElement ? row.textContent || "" : "",
    })),
    status: document.getElementById("tree-shell-status")?.textContent || "",
    lastAction: document.getElementById("tree-shell-last-action")?.textContent || "",
  }));
}

async function main() {
  const result = {
    ok: false,
    task: TASK,
    baseUrl: BASE_URL,
    createdIds: [],
    navigationEvents: [],
    treeCommandRequests: [],
    modes: {},
  };
  const browser = await chromium.launch({ headless: true });
  const context = await browser.newContext();
  const page = await context.newPage();

  page.on("request", (request) => {
    const url = request.url();
    if (url.includes("/api/tree/commands")) {
      result.treeCommandRequests.push({
        method: request.method(),
        url,
        body: request.postData() || null,
        at: Date.now(),
      });
    }
  });

  try {
    await ensureAuthenticated(page, context.request);
    page.on("framenavigated", (frame) => {
      if (frame === page.mainFrame()) {
        result.navigationEvents.push({ url: frame.url(), at: Date.now() });
      }
    });

    for (const mode of ["filetree", "page"]) {
      const root = await createTempDocument(context.request, null);
      result.createdIds.push(root.documentId);
      await renameDocument(
        context.request,
        root.workspaceId,
        root.documentId,
        `task179-tree-${mode}-root-${Date.now().toString().slice(-6)}`,
      );

      const treeUrl = `${BASE_URL}/tree?workspaceId=${encodeURIComponent(root.workspaceId)}&mode=${encodeURIComponent(mode)}&activeDocumentId=${encodeURIComponent(root.documentId)}`;
      await page.goto(treeUrl, { waitUntil: "commit", timeout: UI_TIMEOUT_MS });
      await page.locator(documentRowSelector(mode, root.documentId)).waitFor({
        state: "visible",
        timeout: UI_TIMEOUT_MS,
      });
      const initialUrl = page.url();
      const navigationStartIndex = result.navigationEvents.length;

      const createStartedAt = Date.now();
      await page.getByTestId("tree-create-root").click({ timeout: UI_TIMEOUT_MS });
      const renameInput = page.locator(renameInputSelector(mode)).first();
      await renameInput.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
      const renameId = await renameInput.getAttribute("data-rename-id");
      const createdDocumentId = documentIdFromRenameId(mode, renameId);
      if (!createdDocumentId) throw new Error(`${mode}_created_document_id_missing:${renameId || ""}`);
      result.createdIds.push(createdDocumentId);
      await page.locator(documentRowSelector(mode, createdDocumentId)).waitFor({
        state: "visible",
        timeout: UI_TIMEOUT_MS,
      });
      await page.keyboard.press("Escape");
      const createFinishedAt = Date.now();

      const afterCreateUrl = page.url();
      if (afterCreateUrl !== initialUrl) {
        throw new Error(`${mode}_create_changed_url:${initialUrl}->${afterCreateUrl}`);
      }
      const navigationAfterCreate = result.navigationEvents.slice(navigationStartIndex);
      if (navigationAfterCreate.length !== 0) {
        throw new Error(`${mode}_create_triggered_navigation:${JSON.stringify(navigationAfterCreate)}`);
      }

      let deleteMs = null;
      let afterDeleteUrl = page.url();
      let navigationAfterDelete = result.navigationEvents.slice(navigationStartIndex);
      if (mode === "filetree") {
        const deleteStartedAt = Date.now();
        const createdRow = page.locator(documentRowSelector(mode, createdDocumentId)).first();
        await createdRow.click({ timeout: UI_TIMEOUT_MS });
        await page.keyboard.press("Delete");
        const confirmButton = page.locator('.tree-preflight-actions button[data-role="confirm"]').first();
        await confirmButton.click({ timeout: UI_TIMEOUT_MS });
        await page.locator(documentRowSelector(mode, createdDocumentId)).waitFor({
          state: "detached",
          timeout: UI_TIMEOUT_MS,
        });
        const deleteFinishedAt = Date.now();
        deleteMs = deleteFinishedAt - deleteStartedAt;

        afterDeleteUrl = page.url();
        if (afterDeleteUrl !== initialUrl) {
          throw new Error(`${mode}_delete_changed_url:${initialUrl}->${afterDeleteUrl}`);
        }
        navigationAfterDelete = result.navigationEvents.slice(navigationStartIndex);
        if (navigationAfterDelete.length !== 0) {
          throw new Error(`${mode}_delete_triggered_navigation:${JSON.stringify(navigationAfterDelete)}`);
        }
      }

      result.modes[mode] = {
        timings: {
          createMs: createFinishedAt - createStartedAt,
          deleteMs,
        },
        initialUrl,
        finalUrl: afterDeleteUrl,
        createdDocumentId,
        navigationEvents: navigationAfterDelete,
        finalState: await readShellState(page),
      };
    }
    result.ok = true;
    await writeResult(result);
  } catch (error) {
    result.error = error instanceof Error ? error.stack || error.message : String(error);
    result.failureState = await readShellState(page).catch(() => null);
    await writeResult(result);
    throw error;
  } finally {
    await cleanupDocuments(context.request, result.createdIds).catch(() => undefined);
    await context.close().catch(() => undefined);
    await browser.close().catch(() => undefined);
  }
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});
