import assert from 'node:assert/strict';
import { mkdir, mkdtemp, readFile, stat, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import test from 'node:test';
import { main } from '../cli.js';

test('init, add actor, and configure write package-local SDK state', async () => {
  const root = await mkdtemp(join(tmpdir(), 'matrix-sdk-cli-test.'));

  await main(['init', root, '--name', 'demo-package']);
  await main(['add', 'actor', 'greeter', '--dir', root, '--mount', 'demo.greeter']);
  await main([
    'configure',
    '--dir', root,
    '--key', 'test-key',
    '--cloud', 'https://example.invalid',
    '--space', 'demo-space',
  ]);

  const manifest = JSON.parse(await readFile(join(root, 'matrix.json'), 'utf8'));
  const packageJson = JSON.parse(await readFile(join(root, 'package.json'), 'utf8'));
  assert.equal(packageJson.private, undefined);
  assert.equal(packageJson.dependencies['@open-matrix/sdk'], '^0.1.0');
  assert.equal(manifest.name, 'demo-package');
  assert.equal(manifest.runtime.entry, './dist/index.js');
  assert.deepEqual(manifest.runtime.factory, {
    kind: 'factory',
    export: 'createStandaloneGreeterActor',
    instance: {
      id: 'RUNTIME-HOST-DEMO-GREETER',
      class: 'service',
      rootKind: 'component',
      componentType: 'GreeterActor',
      autoStart: true,
    },
  });
  assert.deepEqual(manifest.components, [{
    type: 'GreeterActor',
    export: 'GreeterActor',
    mount: 'demo.greeter',
    surface: 'headless',
    accepts: ['echo', 'getStatus'],
  }]);

  const actorSource = await readFile(join(root, 'src', 'GreeterActor.ts'), 'utf8');
  assert.match(actorSource, /from '@open-matrix\/sdk'/);
  const factorySource = await readFile(join(root, 'src', 'create-standalone-GreeterActor.ts'), 'utf8');
  assert.match(factorySource, /createStandaloneGreeterActor/);
  assert.match(factorySource, /runtime\.createSupervised\(GreeterActor, mount\)/);
  const credential = JSON.parse(await readFile(join(root, '.matrix', 'credentials', 'matrix-api-key.json'), 'utf8'));
  assert.equal(credential.key, 'test-key');
  assert.equal(credential.cloud, 'https://example.invalid');
  assert.equal(credential.space, 'demo-space');
  const credentialMode = (await stat(join(root, '.matrix', 'credentials', 'matrix-api-key.json'))).mode & 0o777;
  assert.equal(credentialMode, 0o600);
});

test('up delegates a host-runnable package to an explicit managed host command', async () => {
  const root = await mkdtemp(join(tmpdir(), 'matrix-sdk-cli-up-test.'));
  const fakeRuntimeHost = join(root, 'fake-runtime-host.mjs');
  const calledPath = join(root, 'runtime-host-called.json');

  await main(['init', root, '--name', 'demo-package']);
  await main(['add', 'actor', 'greeter', '--dir', root, '--mount', 'demo.greeter']);
  await mkdir(join(root, 'dist'), { recursive: true });
  await writeFile(join(root, 'dist', 'index.js'), 'export function createStandaloneGreeterActor() {}\n', 'utf8');
  await writeFile(fakeRuntimeHost, `
import { writeFileSync } from 'node:fs';
writeFileSync(${JSON.stringify(calledPath)}, JSON.stringify({
  argv: process.argv.slice(2),
  cwd: process.cwd(),
}, null, 2));
`, 'utf8');

  await main([
    'configure',
    '--dir', root,
    '--key', 'test-key',
    '--cloud', 'https://example.invalid',
    '--space', 'demo-space',
    '--runtime-host-bin', fakeRuntimeHost,
    '--runtime-host-routing', 'workspace-source',
  ]);
  await main(['up', '--dir', root, '--json']);

  const call = JSON.parse(await readFile(calledPath, 'utf8'));
  assert.equal(call.cwd, root);
  assert.deepEqual(call.argv.slice(0, 3), ['--workspace-source', 'up', root]);
  assert.ok(call.argv.includes('--json'));
});

test('add actor preserves explicit Actor class suffix', async () => {
  const root = await mkdtemp(join(tmpdir(), 'matrix-sdk-cli-actor-suffix-test.'));

  await main(['init', root, '--name', 'demo-package']);
  await main(['add', 'actor', 'GreeterActor', '--dir', root, '--mount', 'demo.greeter']);

  const manifest = JSON.parse(await readFile(join(root, 'matrix.json'), 'utf8'));
  assert.equal(manifest.runtime.factory.export, 'createStandaloneGreeterActor');
  assert.equal(manifest.runtime.factory.instance.componentType, 'GreeterActor');
  assert.equal(manifest.components[0].type, 'GreeterActor');
  await stat(join(root, 'src', 'GreeterActor.ts'));
  await stat(join(root, 'src', 'create-standalone-GreeterActor.ts'));
});
