import { mkdtemp, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import type { AppConfig } from "../src/config.js";
import { readUpdateStatus } from "../src/update.js";

const temporaryDirectories: string[] = [];

function config(updateStatusPath: string, versionFile: string): AppConfig {
  return {
    nodeEnv: "test",
    host: "127.0.0.1",
    port: 8787,
    databasePath: ":memory:",
    sessionTtlMs: 60_000,
    cookieSecure: false,
    allowedOrigins: new Set(),
    updateStatusPath,
    versionFile,
    network: {
      enabled: false,
      statusPath: join(tmpdir(), "missing-network-status.json"),
      commandPath: join(tmpdir(), "network-command.json"),
      configurationRequestPath: join(tmpdir(), "network-configuration.json"),
      activityPath: join(tmpdir(), "network-activity.json")
    },
    adb: { enabled: false, executable: "adb", serial: null, timeoutMs: 3_000 }
  };
}

afterEach(async () => {
  await Promise.all(temporaryDirectories.splice(0).map((directory) => rm(directory, { recursive: true, force: true })));
});

describe("system update status", () => {
  it("reads only validated updater state and active revision metadata", async () => {
    const directory = await mkdtemp(join(tmpdir(), "pi-car-update-test-"));
    temporaryDirectories.push(directory);
    const statusPath = join(directory, "status.json");
    const versionPath = join(directory, "REVISION");
    await writeFile(
      statusPath,
      JSON.stringify({
        state: "success",
        message: "Update installed.",
        fromRevision: "a".repeat(40),
        toRevision: "b".repeat(40),
        updatedAt: "2026-07-31T18:00:00.000Z"
      })
    );
    await writeFile(versionPath, `${"b".repeat(40)}\n`);

    await expect(readUpdateStatus(config(statusPath, versionPath))).resolves.toMatchObject({
      state: "success",
      installedRevision: "b".repeat(40),
      supported: true
    });
  });

  it("reports a check-only result when a newer revision is available", async () => {
    const directory = await mkdtemp(join(tmpdir(), "pi-car-update-test-"));
    temporaryDirectories.push(directory);
    const statusPath = join(directory, "status.json");
    const versionPath = join(directory, "REVISION");
    await writeFile(
      statusPath,
      JSON.stringify({
        state: "available",
        message: "A newer release is available.",
        fromRevision: "a".repeat(40),
        toRevision: "b".repeat(40),
        updatedAt: "2026-07-31T18:00:00.000Z"
      })
    );
    await writeFile(versionPath, `${"a".repeat(40)}\n`);

    await expect(readUpdateStatus(config(statusPath, versionPath))).resolves.toMatchObject({
      state: "available",
      fromRevision: "a".repeat(40),
      toRevision: "b".repeat(40),
      installedRevision: "a".repeat(40),
      supported: true
    });
  });

  it("treats missing or malformed status files as unsupported", async () => {
    const directory = await mkdtemp(join(tmpdir(), "pi-car-update-test-"));
    temporaryDirectories.push(directory);
    const statusPath = join(directory, "status.json");
    await writeFile(statusPath, "not-json");

    await expect(readUpdateStatus(config(statusPath, join(directory, "missing")))).resolves.toMatchObject({
      state: "idle",
      installedRevision: null,
      supported: false
    });
  });

  it("recovers an update state left running after interruption", async () => {
    const directory = await mkdtemp(join(tmpdir(), "pi-car-update-test-"));
    temporaryDirectories.push(directory);
    const statusPath = join(directory, "status.json");
    await writeFile(
      statusPath,
      JSON.stringify({
        state: "building",
        message: "Building.",
        fromRevision: null,
        toRevision: null,
        updatedAt: "2020-01-01T00:00:00.000Z"
      })
    );

    await expect(readUpdateStatus(config(statusPath, join(directory, "missing")))).resolves.toMatchObject({
      state: "failed",
      supported: true
    });
  });
});
