import test from 'node:test';
import assert from 'node:assert/strict';
import { spawnSync } from 'node:child_process';
import { chmod, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
import { join } from 'node:path';
import { tmpdir } from 'node:os';

const script = new URL('../scripts/bootstrap_selfhost_smolvlm.sh', import.meta.url).pathname;

test('self-host bootstrap reports immutable source and model receipts', () => {
  const result = spawnSync('bash', [script, 'receipt'], { encoding: 'utf8' });

  assert.equal(result.status, 0, result.stderr);
  assert.match(result.stdout, /llama\.cpp commit: [0-9a-f]{40}/);
  assert.match(result.stdout, /SmolVLM2-2\.2B-Instruct-Q4_K_M\.gguf sha256: [0-9a-f]{64}/);
  assert.match(result.stdout, /mmproj-SmolVLM2-2\.2B-Instruct-Q8_0\.gguf sha256: [0-9a-f]{64}/);
  assert.match(result.stdout, /bind address: 127\.0\.0\.1:8080/);
});

test('self-host bootstrap rejects model files that do not match pinned hashes', () => {
  const result = spawnSync('bash', [script, 'verify'], {
    encoding: 'utf8',
    env: { ...process.env, TIMMY_SELFHOST_ROOT: '/tmp/timmy-missing-bootstrap' },
  });

  assert.notEqual(result.status, 0);
  assert.match(result.stderr, /Run .* install|Missing required file/);
});

test('self-host bootstrap completes the pinned private worker lifecycle from an empty directory', async () => {
  const sandbox = await mkdtemp(join(tmpdir(), 'timmy-bootstrap-'));
  const bin = join(sandbox, 'bin');
  const root = join(sandbox, 'worker');
  spawnSync('mkdir', ['-p', bin]);
  const commands = join(sandbox, 'commands.log');
  const tools = {
    git: `#!/bin/sh\nprintf 'git %s\\n' "$*" >> "$COMMAND_LOG"\nif [ "$1" = clone ]; then mkdir -p "$3/.git"; fi\n`,
    cmake: `#!/bin/sh\nprintf 'cmake %s\\n' "$*" >> "$COMMAND_LOG"\nbuild=''; prev=''; for arg in "$@"; do [ "$prev" = --build ] && build="$arg"; prev="$arg"; done\nif [ -n "$build" ]; then mkdir -p "$build/bin"; printf '#!/bin/sh\\n' > "$build/bin/llama-server"; chmod +x "$build/bin/llama-server"; fi\n`,
    curl: `#!/bin/sh\nprintf 'curl %s\\n' "$*" >> "$COMMAND_LOG"\nout=''; prev=''; for arg in "$@"; do { [ "$prev" = -o ] || [ "$prev" = --output ]; } && out="$arg"; prev="$arg"; done\ncase "$out" in *mmproj*) printf 'mmproj\\n' > "$out";; *) printf 'model\\n' > "$out";; esac\n`,
  };
  for (const [name, contents] of Object.entries(tools)) {
    await writeFile(join(bin, name), contents);
    await chmod(join(bin, name), 0o755);
  }

  const result = spawnSync('bash', [script, 'install'], {
    encoding: 'utf8',
    env: {
      ...process.env,
      PATH: `${bin}:${process.env.PATH}`,
      COMMAND_LOG: commands,
      TIMMY_SELFHOST_ROOT: root,
      TIMMY_MODEL_SHA256: '98ad61a25e3683b6adf2474b01bbe1c27de6aad2ce3a80ff4140fe473c14e691',
      TIMMY_MMPROJ_SHA256: 'ce52f16b076dcb922c667c08d62881c85fa26aca7cc60394050d5bb1153b7276',
    },
  });

  assert.equal(result.status, 0, result.stderr);
  const log = await readFile(commands, 'utf8');
  assert.match(log, /git clone https:\/\/github\.com\/ggml-org\/llama\.cpp/);
  assert.match(log, /checkout --detach 6d05498314db1b57f81c271080018aa2d0b89be9/);
  assert.match(log, /curl .*SmolVLM2-2\.2B-Instruct-Q4_K_M\.gguf/);
  assert.match(result.stdout, /Pinned model files verified/);

  const fakeServer = join(root, 'llama.cpp', 'build', 'bin', 'llama-server');
  await writeFile(fakeServer, `#!/usr/bin/env python3
import argparse, json
from http.server import BaseHTTPRequestHandler, HTTPServer
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument('--host'); parser.add_argument('--port', type=int)
args, _ = parser.parse_known_args()
class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        body = json.dumps({'data': [{'id': 'SmolVLM2-2.2B-Instruct'}]}).encode()
        self.send_response(200); self.send_header('Content-Type', 'application/json'); self.end_headers(); self.wfile.write(body)
    def log_message(self, *_): pass
HTTPServer((args.host, args.port), Handler).serve_forever()
`);
  await chmod(fakeServer, 0o755);
  const lifecycleEnv = {
    ...process.env,
    TIMMY_SELFHOST_ROOT: root,
    TIMMY_MODEL_PORT: String(19000 + process.pid % 1000),
    TIMMY_MODEL_SHA256: '98ad61a25e3683b6adf2474b01bbe1c27de6aad2ce3a80ff4140fe473c14e691',
    TIMMY_MMPROJ_SHA256: 'ce52f16b076dcb922c667c08d62881c85fa26aca7cc60394050d5bb1153b7276',
  };
  for (const command of ['start', 'health', 'stop']) {
    const commandResult = spawnSync('bash', [script, command], { encoding: 'utf8', env: lifecycleEnv });
    assert.equal(commandResult.status, 0, `${command}: ${commandResult.stderr}`);
  }
  await rm(sandbox, { recursive: true, force: true });
});
