import {
  describe,
  it,
  expect,
  beforeEach,
  afterEach
} from 'vitest';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import {
  assertPathUnderRoot,
  clearGrantedPluginReadRoots,
  grantPluginReadRoot,
  resolveReadablePath
} from './path-jail';

describe('path-jail', () => {
  let tempRoot = '';

  beforeEach(() => {
    tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'metoyou-path-jail-'));
    fs.mkdirSync(path.join(tempRoot, 'server', 'room-1'), { recursive: true });
    fs.writeFileSync(path.join(tempRoot, 'server', 'room-1', 'file.txt'), 'ok');
  });

  afterEach(() => {
    clearGrantedPluginReadRoots();
    fs.rmSync(tempRoot, { recursive: true, force: true });
  });

  it('accepts paths inside allowed subdirectories', async () => {
    const allowedPath = path.join(tempRoot, 'server', 'room-1', 'file.txt');

    await expect(assertPathUnderRoot(tempRoot, allowedPath, ['server'])).resolves.toBe(allowedPath);
  });

  it('accepts cached plugin bundle paths under plugin-bundles', async () => {
    const bundleDir = path.join(tempRoot, 'plugin-bundles', 'example.plugin', '1.0.0');

    fs.mkdirSync(bundleDir, { recursive: true });
    const bundlePath = path.join(bundleDir, 'main.js');

    fs.writeFileSync(bundlePath, 'export default {}');

    await expect(assertPathUnderRoot(tempRoot, bundlePath)).resolves.toBe(bundlePath);
  });

  it('rejects paths outside the user data root', async () => {
    const outsidePath = path.join(os.tmpdir(), 'outside.txt');

    await expect(assertPathUnderRoot(tempRoot, outsidePath, ['server'])).rejects.toThrow('outside allowed app-data paths');
  });

  it('rejects paths outside allowed subdirectories', async () => {
    const pluginsPath = path.join(tempRoot, 'plugins', 'evil.txt');

    await expect(assertPathUnderRoot(tempRoot, pluginsPath, ['server'])).rejects.toThrow('outside allowed app-data paths');
  });

  it('allows user-granted plugin source roots outside app data', async () => {
    const externalRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'metoyou-plugin-source-'));
    const manifestPath = path.join(externalRoot, 'plugin-source.json');

    fs.writeFileSync(manifestPath, '{}');

    grantPluginReadRoot(externalRoot);

    await expect(resolveReadablePath(manifestPath)).resolves.toBe(manifestPath);

    fs.rmSync(externalRoot, { recursive: true, force: true });
  });
});
