// tests/kb-update/test-cross-platform-paths.test.mjs
// Unit tests for scripts/kb-update/lib/cross-platform-paths.mjs
// Zero deps. Uses node:test + dependency-injection (homedir/platform overrides) to avoid filesystem and OS coupling.

import { test } from 'node:test';
import assert from 'node:assert/strict';
import { mkdtempSync, rmSync, existsSync, statSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import {
  getCacheDir,
  getLogDir,
  getStateDir,
  getBackupDir,
} from '../../scripts/kb-update/lib/cross-platform-paths.mjs';

const APP = 'ms-ai-architect-test';

function withTmp(fn) {
  const dir = mkdtempSync(join(tmpdir(), 'cpp-test-'));
  try {
    return fn(dir);
  } finally {
    rmSync(dir, { recursive: true, force: true });
  }
}

test('getCacheDir — macOS returns ~/Library/Caches/<app>/', () => {
  withTmp((home) => {
    const result = getCacheDir(APP, { platform: 'darwin', homedir: () => home, env: {} });
    assert.equal(result, join(home, 'Library', 'Caches', APP));
    assert.equal(existsSync(result), true);
    assert.equal(statSync(result).isDirectory(), true);
  });
});

test('getCacheDir — Linux uses XDG_CACHE_HOME when set', () => {
  withTmp((home) => {
    const xdg = join(home, 'custom-cache');
    const result = getCacheDir(APP, { platform: 'linux', homedir: () => home, env: { XDG_CACHE_HOME: xdg } });
    assert.equal(result, join(xdg, APP));
    assert.equal(existsSync(result), true);
  });
});

test('getCacheDir — Linux falls back to ~/.cache/<app>/ when no XDG', () => {
  withTmp((home) => {
    const result = getCacheDir(APP, { platform: 'linux', homedir: () => home, env: {} });
    assert.equal(result, join(home, '.cache', APP));
  });
});

test('getCacheDir — Windows uses %LOCALAPPDATA%\\<app>\\Cache', () => {
  withTmp((home) => {
    const lad = join(home, 'AppData', 'Local');
    const result = getCacheDir(APP, { platform: 'win32', homedir: () => home, env: { LOCALAPPDATA: lad } });
    assert.equal(result, join(lad, APP, 'Cache'));
  });
});

test('getLogDir — macOS returns ~/Library/Logs/<app>/', () => {
  withTmp((home) => {
    const result = getLogDir(APP, { platform: 'darwin', homedir: () => home, env: {} });
    assert.equal(result, join(home, 'Library', 'Logs', APP));
  });
});

test('getLogDir — Linux uses XDG_STATE_HOME/<app>/logs when set', () => {
  withTmp((home) => {
    const xdg = join(home, 'custom-state');
    const result = getLogDir(APP, { platform: 'linux', homedir: () => home, env: { XDG_STATE_HOME: xdg } });
    assert.equal(result, join(xdg, APP, 'logs'));
  });
});

test('getLogDir — Linux falls back to ~/.local/state/<app>/logs/', () => {
  withTmp((home) => {
    const result = getLogDir(APP, { platform: 'linux', homedir: () => home, env: {} });
    assert.equal(result, join(home, '.local', 'state', APP, 'logs'));
  });
});

test('getLogDir — Windows uses %LOCALAPPDATA%\\<app>\\Logs', () => {
  withTmp((home) => {
    const lad = join(home, 'AppData', 'Local');
    const result = getLogDir(APP, { platform: 'win32', homedir: () => home, env: { LOCALAPPDATA: lad } });
    assert.equal(result, join(lad, APP, 'Logs'));
  });
});

test('getStateDir — macOS uses ~/Library/Application Support/<app>/', () => {
  withTmp((home) => {
    const result = getStateDir(APP, { platform: 'darwin', homedir: () => home, env: {} });
    assert.equal(result, join(home, 'Library', 'Application Support', APP));
  });
});

test('getStateDir — Linux uses XDG_STATE_HOME when set', () => {
  withTmp((home) => {
    const xdg = join(home, 'custom-state');
    const result = getStateDir(APP, { platform: 'linux', homedir: () => home, env: { XDG_STATE_HOME: xdg } });
    assert.equal(result, join(xdg, APP));
  });
});

test('getBackupDir — joins pluginRoot and .kb-backup, creates if missing', () => {
  withTmp((root) => {
    const result = getBackupDir(root);
    assert.equal(result, join(root, '.kb-backup'));
    assert.equal(existsSync(result), true);
    assert.equal(statSync(result).isDirectory(), true);
  });
});

test('default options — uses real os.homedir() and process.platform', () => {
  // Smoke-test: with no overrides, returns something sane (creates dir under real home).
  // Use an unusual app name to avoid colliding with anything real.
  const APP_REAL = 'ms-ai-architect-cpp-smoke-' + process.pid;
  const result = getCacheDir(APP_REAL);
  assert.ok(result.length > 0);
  assert.equal(existsSync(result), true);
  // Cleanup
  rmSync(result, { recursive: true, force: true });
});

test('getCacheDir — throws on missing app name', () => {
  assert.throws(() => getCacheDir(), /appName/);
  assert.throws(() => getCacheDir(''), /appName/);
});
