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

const assert = require("node:assert");
const { spawn } = require("node:child_process");
const {
  fetchWithTimeout,
  findFreePort,
  waitForGateway,
} = require("./task114-rust-web-gateway-entry-smoke.js");
const { resolveRuntimePlan } = require("./desktop-hot.js");

function buildRetirementFixtureEnv(port) {
  return {
    SKIP_NEXT_LEGACY: "1",
    MNOTE_WEB_ALLOW_DEV_FIXTURES: "1",
    MNOTE_WEB_BIND: `127.0.0.1:${port}`,
    MNOTE_WEB_PUBLIC_BIND: "127.0.0.1:3000",
    MNOTE_WEB_ENABLE_LEGACY_NEXT_COMPAT: "0",
    MNOTE_WEB_QUERY_FIXTURES_JSON: JSON.stringify({
      "documents:getMeta": {
        id: "doc_1",
        workspace_id: "ws_demo",
        title: "服务端页面",
        updated_at: "2026-04-28T00:00:00Z",
        can_edit: true,
        word_count: 42,
        character_count: 128,
        block_count: 3,
      },
      "documents:getContent": {
        content: [{ id: "block_1", type: "paragraph", content: [] }],
        revision: 7,
        conflict_detection_key: "doc_1:7",
        pageSubtree: { rootNodeId: "doc_1", outline: [] },
      },
      "sidebar:datasetList": {
        active_workspace_id: "ws_demo",
        workspaces: [],
        documents: [
          {
            id: "doc_1",
            workspace_id: "ws_demo",
            title: "服务端页面",
            parent_id: null,
            sort_order: 0,
            is_starred: false,
            is_template: false,
            created_at: "2026-04-28T00:00:00Z",
            updated_at: "2026-04-28T00:00:00Z",
          },
        ],
        trashed_documents: [],
        media_assets: [],
        trashed_media_assets: [],
        mindmap_assets: [],
        trashed_mindmap_assets: [],
        table_assets: [],
        trashed_table_assets: [],
        mindmap_docs: [],
        mindmap_asset_children: {},
      },
      "bridgeLogs:listWorkspaceOverview": {
        workspace_id: "ws_demo",
        command_logs: [],
        domain_events: [],
        next_cursor: null,
        has_more: false,
        filters: {
          command_status: null,
          event_status: null,
          target_page_id: null,
          target_block_id: null,
          aggregate_type: null,
          aggregate_id: null,
        },
        generated_at: "2026-04-28T00:00:00Z",
      },
    }),
  };
}

function startRetiredNextGateway(port) {
  return spawn("cargo", ["run", "-q", "-p", "mnote-web", "--bin", "mnote-web"], {
    cwd: "/mnt/Data1T/mnote/rust",
    env: {
      ...process.env,
      ...buildRetirementFixtureEnv(port),
    },
    stdio: ["ignore", "pipe", "pipe"],
  });
}

function authedInit(init = {}) {
  return {
    ...init,
    headers: {
      ...(init.headers || {}),
      "x-mnote-actor-id": "user_real",
      "x-mnote-actor-type": "user",
    },
  };
}

async function readText(baseUrl, path, init) {
  const response = await fetchWithTimeout(`${baseUrl}${path}`, init);
  const text = await response.text();
  assert.equal(response.status, 200, `${path} 请求失败: ${response.status} ${text.slice(0, 200)}`);
  assert.equal(response.headers.get("x-mnote-web-owner"), "mnote-web", `${path} 缺少 mnote-web owner`);
  assert.equal(
    response.headers.get("x-mnote-legacy-upstream"),
    null,
    `${path} 默认主路径不应出现 Next fallback header`,
  );
  return { response, text };
}

async function validateSkipNextRuntimePlan() {
  const plan = resolveRuntimePlan({
    FRONTEND_PORT: "3000",
    NEXT_LEGACY_PORT: "3100",
    MNOTE_WEB_ENABLE_LEGACY_NEXT_COMPAT: "1",
  });
  assert.equal(plan.skipGateway, false);
  assert.equal(plan.skipNextLegacy, true);
  assert.equal(plan.frontendTaskName, null);
  assert.equal(plan.publicPort, 3000);
  assert.equal(plan.legacyPort, 3100);
  assert.equal(plan.mnoteWebEnv.MNOTE_WEB_ENABLE_LEGACY_NEXT_COMPAT, "0");
  assert.equal("MNOTE_WEB_LEGACY_NEXT_BASE_URL" in plan.mnoteWebEnv, false);
  return plan;
}

async function validateCoreShellsWithoutNext(baseUrl) {
  const root = await readText(baseUrl, "/?workspaceId=ws_demo", authedInit());
  assert.match(root.text, /data-mnote-shell="workspace"/);
  assert.doesNotMatch(root.text, /next-app-router/i);

  const auth = await readText(baseUrl, "/auth");
  assert.match(auth.text, /data-mnote-shell="auth"/);
  assert.doesNotMatch(auth.text, /next-app-router/i);

  const document = await readText(baseUrl, "/documents/doc_1?workspaceId=ws_demo", authedInit());
  assert.equal(document.response.headers.get("x-mnote-web-shell"), "document");
  assert.match(document.text, /mnote\.page_aggregate\.v1/);

  const treeEvents = await fetchWithTimeout(`${baseUrl}/api/tree/events?workspaceId=ws_demo&maxPolls=0`, authedInit());
  const treeBody = await treeEvents.text();
  assert.equal(treeEvents.status, 200, `/api/tree/events 请求失败: ${treeEvents.status} ${treeBody.slice(0, 200)}`);
  assert.equal(treeEvents.headers.get("x-mnote-web-owner"), "mnote-web");
  assert.equal(treeEvents.headers.get("x-mnote-tree-stream-owner"), "rust-web");
  assert.match(treeBody, /event:\s*snapshot/);

  const search = await readText(baseUrl, "/search?workspaceId=ws_demo&q=Rust", authedInit());
  assert.equal(search.response.headers.get("x-mnote-web-shell"), "search");
  assert.match(search.text, /mnote\.search_shell\.v1/);

  const mindmap = await readText(baseUrl, "/mindmap/doc_1/mind_1", authedInit());
  assert.equal(mindmap.response.headers.get("x-mnote-web-shell"), "mindmap");
  assert.match(mindmap.text, /mnote\.mindmap_shell\.v1/);
  assert.doesNotMatch(mindmap.text, /next-app-router/i);
}

async function validateDocs() {
  const fs = require("node:fs");
  const architecture = fs.readFileSync("/mnt/Data1T/mnote/ARCHITECTURE.md", "utf8");
  assert.match(architecture, /Next App Router.*legacy compat/is, "ARCHITECTURE.md 未标记 Next App Router legacy compat");
  assert.doesNotMatch(architecture, /Next App Router 仍是当前 legacy 主壳/, "ARCHITECTURE.md 仍保留旧主壳口径");
}

async function main() {
  const plan = await validateSkipNextRuntimePlan();
  const port = await findFreePort();
  const baseUrl = `http://127.0.0.1:${port}`;
  const gateway = startRetiredNextGateway(port);
  let stderr = "";
  gateway.stderr.on("data", (chunk) => {
    stderr += chunk.toString("utf8");
  });

  try {
    await waitForGateway(baseUrl);
    await validateCoreShellsWithoutNext(baseUrl);
    await validateDocs();
    console.log(
      JSON.stringify(
        {
          ok: true,
          baseUrl,
          publicEntry: String(plan.publicPort),
          legacyPort: String(plan.legacyPort),
          nextLegacyStarted: false,
          owner: "mnote-web",
        },
        null,
        2,
      ),
    );
  } catch (error) {
    if (stderr.trim()) {
      console.error(stderr.trim().slice(-2000));
    }
    throw error;
  } finally {
    if (gateway.pid) {
      gateway.kill("SIGTERM");
      setTimeout(() => {
        if (!gateway.killed) {
          gateway.kill("SIGKILL");
        }
      }, 2000).unref();
    }
  }
}

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