import assert from "node:assert/strict";
import test from "node:test";
import { createDeploymentController } from "./controller.mjs";

test("deploy update path uses exact maintenance-window ordering", async () => {
  const controller = createDeploymentController({
    async loadConfiguration() {
      return { env: {} };
    },
    async preflight() {},
    async configure(config) {
      return config;
    },
    async checkDependencies() {},
    async selectPorts(config) {
      return config;
    },
    async writeConfiguration() {},
    async isRunning() {
      return true;
    },
    async stop() {},
    async installProject() {},
    async buildTypeScript() {},
    async buildWeb() {},
    async buildTui() {},
    async verifyPorts() {},
    async start() {},
    async waitForHealth() {},
    async markHealthy() {},
    async reportFailure() {}
  });

  const result = await controller.run({ command: "deploy", reconfigure: false, nonInteractive: true });
  assert.deepEqual(result.calls, [
    "load-config",
    "preflight",
    "configure",
    "check-dependencies",
    "select-ports",
    "write-config",
    "stop-old",
    "install",
    "build-typescript",
    "build-web",
    "build-tui",
    "verify-ports-again",
    "start",
    "wait-for-health",
    "mark-healthy"
  ]);
  assert.ok(!result.calls.includes("start-tui"));
});

test("build failure after stop never starts and reports maintenance window", async () => {
  let failure;
  const controller = createDeploymentController({
    async loadConfiguration() {
      return { env: {} };
    },
    async preflight() {},
    async configure(config) {
      return config;
    },
    async checkDependencies() {},
    async selectPorts(config) {
      return config;
    },
    async writeConfiguration() {},
    async isRunning() {
      return true;
    },
    async stop() {},
    async installProject() {},
    async buildTypeScript() {
      const error = new Error("build failed");
      error.logPath = "storage/logs/deploy-20260722.log";
      throw error;
    },
    async buildWeb() {},
    async buildTui() {},
    async verifyPorts() {},
    async start() {},
    async waitForHealth() {},
    async markHealthy() {},
    async reportFailure(details) {
      failure = details;
    }
  });

  const storage = { sentinel: Buffer.from("keep-me") };
  await assert.rejects(
    () => controller.run({ command: "deploy", reconfigure: false, nonInteractive: true }),
    /build failed/
  );
  assert.ok(!failure.calls.includes("start"));
  assert.ok(failure.calls.includes("stop-old"));
  assert.equal(failure.maintenanceWindow, true);
  assert.equal(failure.serviceStopped, true);
  assert.equal(failure.stage, "build-typescript");
  assert.equal(storage.sentinel.toString(), "keep-me");
});

test("stop and help dispatch", async () => {
  const calls = [];
  const controller = createDeploymentController({
    async stop() {
      calls.push("stop");
    },
    async printHelp() {
      calls.push("help");
    }
  });
  await controller.run({ command: "stop" });
  await controller.run({ command: "help" });
  assert.deepEqual(calls, ["stop", "help"]);
});

test("optional tui command checks readiness and API then starts foreground client", async () => {
  const calls = [];
  const controller = createDeploymentController({
    async loadConfiguration() {
      calls.push("load-config");
      return { env: { API_PORT: "8787" } };
    },
    async ensureTuiReady() {
      calls.push("ensure-tui-ready");
    },
    async checkApiForTui() {
      calls.push("check-api-for-tui");
    },
    async startTui(_config, parsed) {
      calls.push(`start-tui:${parsed.runtimeUrl ?? "default"}`);
    }
  });
  await controller.run({
    command: "tui",
    reconfigure: false,
    nonInteractive: false,
    runtimeUrl: "http://127.0.0.1:9000/api/copilotkit"
  });
  assert.deepEqual(calls, [
    "load-config",
    "ensure-tui-ready",
    "check-api-for-tui",
    "start-tui:http://127.0.0.1:9000/api/copilotkit"
  ]);
});

test("tui aborts before start when API check fails", async () => {
  const calls = [];
  const controller = createDeploymentController({
    async loadConfiguration() {
      return { env: { API_PORT: "8787" } };
    },
    async ensureTuiReady() {
      calls.push("ensure-tui-ready");
    },
    async checkApiForTui() {
      calls.push("check-api-for-tui");
      throw new Error("API is not healthy");
    },
    async startTui() {
      calls.push("start-tui");
    }
  });
  await assert.rejects(() => controller.run({ command: "tui", runtimeUrl: null }), /API is not healthy/);
  assert.deepEqual(calls, ["ensure-tui-ready", "check-api-for-tui"]);
  assert.ok(!calls.includes("start-tui"));
});