import { mkdtemp, readFile, 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 {
  consumeHotspotConfigurationRequest,
  consumeNetworkCommand,
  hotspotConfigurationSchema,
  readNetworkStatus,
  requestHotspotConfiguration,
  requestNetworkAction
} from "../src/network.js";

const directories: string[] = [];

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

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

describe("network control boundary", () => {
  it("writes and consumes only fixed action requests", async () => {
    const directory = await mkdtemp(join(tmpdir(), "pi-car-network-test-"));
    directories.push(directory);
    const testConfig = config(directory);
    const requested = await requestNetworkAction(testConfig, "retry-upstream", 7);
    expect(JSON.parse(await readFile(testConfig.network.commandPath, "utf8"))).toMatchObject({
      id: requested.id,
      action: "retry-upstream",
      actorUserId: 7
    });
    await expect(consumeNetworkCommand(testConfig.network.commandPath)).resolves.toMatchObject({ action: "retry-upstream" });
    await expect(consumeNetworkCommand(testConfig.network.commandPath)).resolves.toBeNull();
  });

  it("rejects malformed controller status", async () => {
    const directory = await mkdtemp(join(tmpdir(), "pi-car-network-test-"));
    directories.push(directory);
    const testConfig = config(directory);
    await writeFile(testConfig.network.statusPath, '{"mode":"shell"}');
    await expect(readNetworkStatus(testConfig)).resolves.toMatchObject({ supported: false, mode: "starting" });
  });

  it("validates and transfers hotspot credentials only through the root request file", async () => {
    const directory = await mkdtemp(join(tmpdir(), "pi-car-network-test-"));
    directories.push(directory);
    const testConfig = config(directory, false);
    expect(hotspotConfigurationSchema.safeParse({ ssid: "MG4 Car", password: "Strong pass!2" }).success).toBe(true);
    expect(hotspotConfigurationSchema.safeParse({ ssid: "bad/name", password: "Strong pass!2" }).success).toBe(false);
    expect(hotspotConfigurationSchema.safeParse({ ssid: "MG4 Car", password: "short" }).success).toBe(false);

    await requestHotspotConfiguration(testConfig, { ssid: "MG4 Car", password: "Strong pass!2" }, 7, async () => undefined);
    await expect(consumeHotspotConfigurationRequest(testConfig.network.configurationRequestPath)).resolves.toMatchObject({
      ssid: "MG4 Car",
      password: "Strong pass!2",
      actorUserId: 7
    });
    await expect(readFile(testConfig.network.configurationRequestPath, "utf8")).rejects.toThrow();
  });
});
