import test from "node:test";
import assert from "node:assert/strict";
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join, resolve } from "node:path";
import {
  enumerateValidAccountIds,
  getAccountsDirFromEnv,
  _resetEnumerationCache,
} from "../index.js";

function makeFixture(): string {
  const root = mkdtempSync(join(tmpdir(), "acct-enum-"));
  // (a) non-UUID dir → excluded.
  mkdirSync(join(root, "not-a-uuid"));
  writeFileSync(join(root, "not-a-uuid", "account.json"), "{}");
  // (b) UUID dir, no account.json → excluded.
  mkdirSync(join(root, "11111111-2222-3333-4444-555555555555"));
  // (c) UUID dir, unparseable account.json → excluded (over-prune doctrine).
  mkdirSync(join(root, "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"));
  writeFileSync(
    join(root, "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "account.json"),
    "{ broken json",
  );
  // (d) UUID dir, parseable account.json → included.
  mkdirSync(join(root, "12345678-9abc-def0-1234-56789abcdef0"));
  writeFileSync(
    join(root, "12345678-9abc-def0-1234-56789abcdef0", "account.json"),
    JSON.stringify({ id: "12345678-9abc-def0-1234-56789abcdef0" }),
  );
  return root;
}

test("enumerateValidAccountIds returns only UUID dirs with parseable account.json", () => {
  _resetEnumerationCache();
  const root = makeFixture();
  try {
    const result = enumerateValidAccountIds(root);
    assert.deepEqual(result, ["12345678-9abc-def0-1234-56789abcdef0"]);
  } finally {
    rmSync(root, { recursive: true });
  }
});

test("enumerateValidAccountIds returns [] when accountsDir does not exist", () => {
  _resetEnumerationCache();
  const ghost = join(tmpdir(), "acct-enum-does-not-exist-" + Date.now());
  assert.deepEqual(enumerateValidAccountIds(ghost), []);
});

test("enumerateValidAccountIds caches per accountsDir; reset re-reads", () => {
  _resetEnumerationCache();
  const root = makeFixture();
  try {
    const first = enumerateValidAccountIds(root);
    // Add a second valid dir AFTER first call; cached call must NOT see it.
    const newId = "99999999-aaaa-bbbb-cccc-dddddddddddd";
    mkdirSync(join(root, newId));
    writeFileSync(join(root, newId, "account.json"), "{}");
    const cached = enumerateValidAccountIds(root);
    assert.deepEqual(cached, first, "cache should hide the newly-added dir");
    _resetEnumerationCache();
    const fresh = enumerateValidAccountIds(root);
    assert.equal(fresh.length, 2);
    assert.ok(fresh.includes(newId));
  } finally {
    rmSync(root, { recursive: true });
  }
});

test("getAccountsDirFromEnv throws when MAXY_PLATFORM_ROOT is unset", () => {
  const saved = process.env.MAXY_PLATFORM_ROOT;
  delete process.env.MAXY_PLATFORM_ROOT;
  try {
    assert.throws(
      () => getAccountsDirFromEnv(),
      /MAXY_PLATFORM_ROOT not set/,
    );
  } finally {
    if (saved !== undefined) process.env.MAXY_PLATFORM_ROOT = saved;
  }
});

test("getAccountsDirFromEnv resolves to ${root}/../data/accounts when set", () => {
  const saved = process.env.MAXY_PLATFORM_ROOT;
  process.env.MAXY_PLATFORM_ROOT = "/tmp/fake-root/platform";
  try {
    const result = getAccountsDirFromEnv();
    assert.equal(result, resolve("/tmp/fake-root/platform", "..", "data/accounts"));
  } finally {
    if (saved !== undefined) process.env.MAXY_PLATFORM_ROOT = saved;
    else delete process.env.MAXY_PLATFORM_ROOT;
  }
});
