import test from "node:test";
import assert from "node:assert/strict";
import { execFile } from "node:child_process";
import { mkdtemp, mkdir, writeFile } from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { promisify } from "node:util";

const execFileAsync = promisify(execFile);
const root = path.resolve(import.meta.dirname, "..");

async function dockerAvailable() {
	try {
		await execFileAsync("docker", ["info"], { timeout: 15_000 });
		return true;
	} catch {
		return false;
	}
}

test("Docker image starts against PostgreSQL and applies migrations", async (t) => {
	if (!(await dockerAvailable())) {
		t.skip("Docker daemon is unavailable");
		return;
	}
	const temp = await mkdtemp(
		path.join(os.tmpdir(), "roast-planner-container-"),
	);
	const agentDir = path.join(temp, "pi-agent");
	await mkdir(agentDir);
	const envFile = path.join(temp, "compose.env");
	await writeFile(
		envFile,
		`POSTGRES_PASSWORD=container-test-password\nBOOTSTRAP_SETUP_TOKEN=\nPI_AGENT_CONFIG_DIR=${agentDir}\nAPP_PORT=18090\n`,
	);
	const project = `roastplanner${Date.now()}`;
	const compose = (args, options = {}) =>
		execFileAsync(
			"docker",
			["compose", "--project-name", project, "--env-file", envFile, ...args],
			{ cwd: root, timeout: 120_000, ...options },
		);
	t.after(async () => {
		try {
			await compose(["down", "--volumes", "--remove-orphans"]);
		} catch {
			// Preserve the startup failure rather than masking it with cleanup.
		}
	});
	await compose(["up", "--build", "--detach"]);

	let lastError;
	for (let attempt = 0; attempt < 30; attempt++) {
		try {
			await compose([
				"exec",
				"-T",
				"app",
				"node",
				"--input-type=module",
				"-e",
				"const response = await fetch('http://127.0.0.1:8090/'); process.exit(response.ok ? 0 : 1)",
			]);
			lastError = null;
			break;
		} catch (error) {
			lastError = error;
			await new Promise((resolve) => setTimeout(resolve, 1_000));
		}
	}
	assert.equal(
		lastError,
		null,
		"application never became ready in its container",
	);
	const migration = await compose([
		"exec",
		"-T",
		"db",
		"psql",
		"-U",
		"roast",
		"-d",
		"roast",
		"-tAc",
		"SELECT count(*) FROM schema_migrations WHERE filename = '001_auth.sql'",
	]);
	assert.equal(migration.stdout.trim(), "1");
});
