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

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

const ROOT = process.env.MNOTE_REPO_ROOT || "/mnt/Data1T/mnote";
const { BASE_URL, UI_TIMEOUT_MS } = require(path.join(ROOT, "scripts", "tree-shell-smoke-helpers"));

const OUTPUT_DIR = path.join(ROOT, "tmp", "task531-lightrag-dashboard-ui-smoke");
const RESULT_PATH = path.join(OUTPUT_DIR, "result.json");
const CHROME = process.env.MNOTE_PAGE_AI_CHROME || "/usr/bin/google-chrome";

async function fetchDashboardStatus(context) {
  const response = await context.request.get(`${BASE_URL}/api/knowledge-rag/status`, {
    headers: {
      "x-mnote-actor-id": "mnote-e2e",
      "x-mnote-actor-type": "user",
      "x-mnote-workspace-id": "local-ws:mnote-e2e:my-space",
    },
    timeout: UI_TIMEOUT_MS,
  });
  const text = await response.text();
  assert(response.ok(), `/api/knowledge-rag/status 失败: ${response.status()} ${text.slice(0, 500)}`);
  const payload = JSON.parse(text);
  assert(payload.dashboardUrl, `status 缺少 dashboardUrl: ${text.slice(0, 500)}`);
  assert(payload.health?.healthy !== false, `LightRAG health 非 healthy: ${text.slice(0, 500)}`);
  return payload;
}

async function bodyText(page) {
  return await page.evaluate(() => document.body.innerText || "");
}

async function screenshot(page, name) {
  const screenshotPath = path.join(OUTPUT_DIR, name);
  await page.screenshot({ path: screenshotPath, fullPage: true });
  return screenshotPath;
}

async function main() {
  fs.mkdirSync(OUTPUT_DIR, { recursive: true });
  const browser = await chromium.launch({
    headless: process.env.MNOTE_DASHBOARD_SMOKE_HEADED !== "1",
    executablePath: fs.existsSync(CHROME) ? CHROME : undefined,
  });
  const context = await browser.newContext({ viewport: { width: 1440, height: 960 } });
  const page = await context.newPage();
  const pageErrors = [];
  const consoleErrors = [];
  page.on("pageerror", (error) => pageErrors.push(String(error?.message || error)));
  page.on("console", (message) => {
    if (message.type() === "error") consoleErrors.push(message.text());
  });

  try {
    const statusPayload = await fetchDashboardStatus(context);
    const dashboardUrl = statusPayload.dashboardUrl;
    const documentSummaries = Array.isArray(statusPayload.documents?.documents)
      ? statusPayload.documents.documents
      : [];
    const rawStatusGroups = statusPayload.documents?.rawStatusGroups || {};
    const processedCount = Number(rawStatusGroups.processed || 0);
    const webuiUrl = dashboardUrl.endsWith("/webui/") ? dashboardUrl : `${dashboardUrl.replace(/\/+$/, "")}/webui/`;
    await page.goto(webuiUrl, { waitUntil: "domcontentloaded", timeout: UI_TIMEOUT_MS });
    await page.waitForLoadState("networkidle", { timeout: UI_TIMEOUT_MS }).catch(() => undefined);
    await page.waitForFunction(
      () => (document.body.innerText || "").includes("Document Management"),
      null,
      { timeout: UI_TIMEOUT_MS },
    );

    const documentsText = await bodyText(page);
    assert(documentsText.includes("Uploaded Documents"), "Documents 页缺少 Uploaded Documents");
    if (processedCount > 0) {
      assert(
        documentsText.includes(`Completed (${processedCount})`),
        `Documents 页未显示当前 completed 计数 ${processedCount}: ${documentsText.slice(0, 1000)}`,
      );
    }
    const visibleDocument = documentSummaries.find((doc) => {
      const id = String(doc.id || "");
      const filePath = String(doc.filePath || "");
      return (id && documentsText.includes(id)) || (filePath && documentsText.includes(filePath));
    });
    assert(
      visibleDocument,
      `Documents 页没有显示 status API 返回的任一当前文档: ${JSON.stringify(documentSummaries.slice(0, 5), null, 2)}\n${documentsText.slice(0, 1000)}`,
    );
    const documentsScreenshot = await screenshot(page, "documents.png");

    await page.getByRole("tab", { name: /Knowledge Graph/i }).click({ timeout: UI_TIMEOUT_MS });
    await page.waitForFunction(
      () => {
        const text = document.body.innerText || "";
        return text.includes("Connected") && text.includes("D:");
      },
      null,
      { timeout: UI_TIMEOUT_MS },
    );
    const graphText = await bodyText(page);
    assert(graphText.includes("Connected"), `Graph 页缺少连接状态: ${graphText.slice(0, 1000)}`);
    const graphScreenshot = await screenshot(page, "graph.png");

    await page.getByRole("tab", { name: /Retrieval/i }).click({ timeout: UI_TIMEOUT_MS });
    await page.waitForFunction(
      () => (document.body.innerText || "").includes("Start a retrieval by typing your query below"),
      null,
      { timeout: UI_TIMEOUT_MS },
    );
    const retrievalText = await bodyText(page);
    assert(retrievalText.includes("Query Mode"), "Retrieval 页缺少 Query Mode 参数");
    assert(retrievalText.includes("KG Top K"), "Retrieval 页缺少 KG Top K 参数");
    assert(retrievalText.includes("Connected"), "Retrieval 页缺少连接状态");
    const retrievalScreenshot = await screenshot(page, "retrieval.png");

    const result = {
      ok: true,
      baseUrl: BASE_URL,
      dashboardUrl,
      webuiUrl: page.url(),
      documents: {
        processedCount,
        completedVisible: processedCount > 0 ? documentsText.includes(`Completed (${processedCount})`) : null,
        visibleDocumentId: visibleDocument.id || null,
        visibleDocumentFilePath: visibleDocument.filePath || null,
        screenshot: documentsScreenshot,
      },
      graph: {
        connectedVisible: graphText.includes("Connected"),
        screenshot: graphScreenshot,
      },
      retrieval: {
        queryModeVisible: retrievalText.includes("Query Mode"),
        connectedVisible: retrievalText.includes("Connected"),
        screenshot: retrievalScreenshot,
      },
      pageErrors,
      consoleErrors,
    };
    fs.writeFileSync(RESULT_PATH, `${JSON.stringify(result, null, 2)}\n`, "utf8");
    console.log(JSON.stringify(result, null, 2));
  } catch (error) {
    await page.screenshot({ path: path.join(OUTPUT_DIR, "failure.png"), fullPage: true }).catch(() => undefined);
    fs.writeFileSync(
      path.join(OUTPUT_DIR, "failure.json"),
      `${JSON.stringify(
        {
          ok: false,
          error: error instanceof Error ? error.stack || error.message : String(error),
          pageErrors,
          consoleErrors,
        },
        null,
        2,
      )}\n`,
      "utf8",
    );
    throw error;
  } finally {
    await browser.close().catch(() => undefined);
  }
}

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