import test from "node:test";
import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";

test("accounts feature exposes safe management UI and mobile controls", async () => {
  const [app, panel, controller, api, css] = await Promise.all([
    readFile(new URL("../../App.jsx", import.meta.url), "utf8"),
    readFile(new URL("./AccountsPanel.jsx", import.meta.url), "utf8"),
    readFile(new URL("./useAccounts.js", import.meta.url), "utf8"),
    readFile(new URL("./accounts-api.js", import.meta.url), "utf8"),
    readFile(new URL("./accounts.css", import.meta.url), "utf8")
  ]);
  assert.match(app, /useAccounts/);
  assert.match(panel, /accountDisplayName/);
  assert.match(panel, /accountStatusLabel/);
  assert.doesNotMatch(panel, /Email or label|person@example\.com/);
  assert.match(panel, /t\("account\.add"\)/);
  assert.match(panel, /account-add-trigger[\s\S]*event\.stopPropagation\(\);\s*manager\.add\(\)/);
  assert.match(panel, /t\("account\.empty"\)/);
  assert.match(panel, /t\("account\.empty"\)/);
  assert.match(panel, /t\("account\.remove"\)/);
  assert.doesNotMatch(panel, /Connect/);
  assert.doesNotMatch(panel, />Edit</);
  assert.match(panel, /t\("account\.note"\)/);
  assert.doesNotMatch(panel, /codexHome|auth\.json|CODEX_HOME/);
  assert.match(css, /font-size:\s*16px/);
  assert.match(css, /min-height:\s*48px/);
  assert.match(css, /\.account-row\{[^}]*grid-template-columns:minmax\(0,1fr\) auto/s);
  assert.match(controller, /function add\(\{ bypassPro = false \} = \{\}\) \{[\s\S]*?onProRequired\(\)[\s\S]*?setLogin\(\{ kind: "new" \}\);\s*return true;\s*\}/);
  assert.match(controller, /async function requestLoginCode\(\)/);
  assert.match(controller, /requestLoginCode[\s\S]*startAccountLoginAttempt\(\)/);
  assert.match(controller, /requestLoginCode[\s\S]*setLogin\(\{ \.\.\.result, kind: "new" \}\)/);
  assert.match(controller, /useEffect\(\(\) => \{[\s\S]*login\.attemptId[\s\S]*setInterval\(\(\) => void poll\(\), 1000\)[\s\S]*clearInterval\(timer\)/);
  assert.match(controller, /await checkConnection\(true\)/);
  assert.match(controller, /completeAccountLoginAttempt\(login\.attemptId\)/);
  assert.match(controller, /function dismissLogin\(\) \{\s*setLogin\(null\);\s*\}/);
  assert.doesNotMatch(controller, /cancelAccountLoginAttempt/);
  assert.doesNotMatch(controller, /createAccount\(\)/);
  assert.doesNotMatch(controller, /replaceAccounts\(result\.accounts, result\.account\.id\)/);
  assert.doesNotMatch(controller, /replaceAccounts\(result\.accounts, accountId\)/);
  assert.match(panel, /account_login_rate_limited/);
  assert.match(panel, /account\.rateLimited/);
  assert.match(panel, /account-add-trigger[\s\S]*account-login-rate-limit/);
  assert.match(css, /\.account-login-rate-limit\{[^}]*font-size:\s*12px[^}]*color:\s*#ff9d9d/s);
  assert.match(api, /login\/complete/);
  assert.match(controller, /completeAccountLogin\(login\.accountId\)/);
  assert.doesNotMatch(controller, /replaceAccounts\(result\.accounts, result\.existingAccountId\)/);
  assert.doesNotMatch(panel, /Removing\?\?|Starting\?\?|횞/);
});

test("failed account operations preserve the current account projection", async () => {
  const controller = await readFile(new URL("./useAccounts.js", import.meta.url), "utf8");
  const startIndex = controller.indexOf("const result = await startAccountLoginAttempt()");
  const completeIndex = controller.indexOf("await completeAccountLoginAttempt(login.attemptId)");
  const replaceIndex = controller.indexOf("replaceAccounts(result.accounts)", completeIndex);

  assert.ok(startIndex >= 0);
  assert.ok(completeIndex > startIndex);
  assert.ok(replaceIndex > completeIndex, "account list must change only after the transient login completes");
  assert.doesNotMatch(controller, /mutation\.failed", error: error\.message/);
  assert.match(controller, /accountMutationError/);
});
