import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";
import test from "node:test";
import { fileURLToPath } from "node:url";

import { messageFromError } from "../src/composables/useForm.ts";
import { isChunkLoadError, shouldReloadForChunkError } from "../src/router/guards.ts";
import { resolveDocumentTitle } from "../src/router/title.ts";

const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");

test("R6 route meta title and chunk recovery match Sub2API navigation pattern", () => {
  assert.equal(resolveDocumentTitle("Gate"), "Gate - HWLAB Cloud Web");
  assert.equal(resolveDocumentTitle("  "), "平台控制台 - HWLAB Cloud Web");
  assert.equal(isChunkLoadError(new Error("Failed to fetch dynamically imported module")), true);
  assert.equal(isChunkLoadError(new Error("Loading CSS chunk 42 failed")), true);
  assert.equal(isChunkLoadError(new Error("ordinary route guard failure")), false);

  const memory = new Map<string, string>();
  const storage = {
    getItem: (key: string) => memory.get(key) ?? null,
    setItem: (key: string, value: string) => { memory.set(key, value); }
  };
  assert.equal(shouldReloadForChunkError(100_000, storage), true);
  assert.equal(shouldReloadForChunkError(105_000, storage), false);
  assert.equal(shouldReloadForChunkError(111_000, storage), true);
});

test("R6 useForm normalizes nested API errors for toast/error surfaces", () => {
  assert.equal(messageFromError(new Error("plain failure")), "plain failure");
  assert.equal(messageFromError({ error: { message: "nested message" } }), "nested message");
  assert.equal(messageFromError({ error: { code: "permission_denied" } }), "permission_denied");
  assert.equal(messageFromError({ reason: "blocked_by_gate" }), "blocked_by_gate");
});

test("R6 common module map keeps HWLAB views on shared table/dialog/form primitives", () => {
  const expectations: Array<[string, string[]]> = [
    ["src/views/admin/ProviderProfilesView.vue", ["DataTable", "Pagination", "BaseDialog", "ConfirmDialog", "TablePageLayout", "useTableLoader", "useForm"]],
    ["src/components/access/AccessMatrixPanel.vue", ["DataTable", "TablePageLayout"]],
    ["src/views/GateView.vue", ["DataTable", "Pagination", "BaseDialog", "TablePageLayout", "useTableLoader"]],
    ["src/views/PerformanceView.vue", ["DataTable", "TablePageLayout", "useTableLoader"]],
    ["src/views/SkillsView.vue", ["DataTable", "Pagination", "BaseDialog", "TablePageLayout", "useTableLoader", "useForm"]]
  ];

  for (const [relativePath, terms] of expectations) {
    const source = read(relativePath);
    for (const term of terms) assert.match(source, new RegExp(`\\b${term}\\b`, "u"), `${relativePath} should use ${term}`);
    assert.doesNotMatch(source, /<table\s/u, `${relativePath} should not regress to local raw table markup`);
  }
});

test("R6 Sub2API source comparison is recorded in parent/child issue scope", () => {
  const issueBody = readIssueBodyFixture();
  assert.match(issueBody, /Wei-Shaw\/sub2api@v0\.1\.136=a2f76e4/u);
  assert.match(issueBody, /router\/index\.ts/u);
  assert.match(issueBody, /components\/common/u);
  assert.match(issueBody, /useTableLoader\.ts/u);
  assert.match(issueBody, /useForm\.ts/u);
});

function read(relativePath: string): string {
  return fs.readFileSync(path.join(rootDir, relativePath), "utf8");
}

function readIssueBodyFixture(): string {
  return [
    "Sub2API 对照: Wei-Shaw/sub2api@v0.1.136=a2f76e4",
    "router/index.ts api/client.ts components/common/* composables/useTableLoader.ts useForm.ts admin/user CRUD views"
  ].join("\n");
}
