import { assertEquals } from 'jsr:@std/assert';

const shouldRunDockerSmoke = Deno.env.get('OBJST_RUN_DOCKER_SMOKE') === '1';

interface ICommandResult {
  code: number;
  stdout: string;
  stderr: string;
}

async function runCommand(
  command: string[],
  options: { cwd?: string; check?: boolean } = {},
): Promise<ICommandResult> {
  const output = await new Deno.Command(command[0], {
    args: command.slice(1),
    cwd: options.cwd,
    stdout: 'piped',
    stderr: 'piped',
  }).output();

  const result = {
    code: output.code,
    stdout: new TextDecoder().decode(output.stdout).trim(),
    stderr: new TextDecoder().decode(output.stderr).trim(),
  };

  if (options.check !== false && result.code !== 0) {
    throw new Error(`Command failed: ${command.join(' ')}\n${result.stderr}`);
  }

  return result;
}

async function waitForOk(url: string, timeoutMs: number): Promise<void> {
  const deadline = Date.now() + timeoutMs;

  while (Date.now() < deadline) {
    try {
      const response = await fetch(url);
      if (response.ok) {
        return;
      }
    } catch {
      // Container may still be starting.
    }

    await new Promise((resolve) => setTimeout(resolve, 1000));
  }

  throw new Error(`Timed out waiting for ${url}`);
}

Deno.test({
  name: 'Docker image builds and serves the management UI',
  ignore: !shouldRunDockerSmoke,
  sanitizeOps: false,
  sanitizeResources: false,
  fn: async () => {
    await runCommand(['docker', '--version']);

    const imageTag = `objectstorage-smoke:${crypto.randomUUID().slice(0, 8)}`;
    const containerName = `objectstorage-smoke-${crypto.randomUUID().slice(0, 8)}`;
    const storagePort = 19190;
    const uiPort = 19191;

    try {
      await runCommand(['docker', 'build', '-t', imageTag, '.']);

      const runResult = await runCommand([
        'docker',
        'run',
        '-d',
        '--name',
        containerName,
        '-p',
        `${storagePort}:9000`,
        '-p',
        `${uiPort}:3000`,
        '-e',
        'OBJST_ADMIN_PASSWORD=docker-smoke-admin',
        '-e',
        'OBJST_ACCESS_KEY=docker-smoke-key',
        '-e',
        'OBJST_SECRET_KEY=docker-smoke-secret',
        imageTag,
      ]);

      assertEquals(runResult.stdout.length > 0, true);
      await waitForOk(`http://127.0.0.1:${uiPort}/readyz`, 30000);
      await waitForOk(`http://127.0.0.1:${storagePort}/-/ready`, 30000);
    } finally {
      await runCommand(['docker', 'rm', '-f', containerName], { check: false });
      await runCommand(['docker', 'rmi', '-f', imageTag], { check: false });
    }
  },
});
