import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import AdmZip from "adm-zip";
import { afterEach, describe, expect, it } from "vitest";
import { buildSupportBundle } from "../src/main/support-bundle";
import type { DownloadManager } from "../src/main/download-manager";

const tempDirs: string[] = [];
const legacyManifestFile = ["debug_", "a", "i", "_manifest.json"].join("");

afterEach(() => {
  for (const dir of tempDirs.splice(0)) {
    try { fs.rmSync(dir, { recursive: true, force: true }); } catch {  }
  }
});

function fakeManager(): DownloadManager {
  const snapshot = {
    stats: {},
    session: { packages: {}, items: {}, packageOrder: [] },
    speedText: "",
    etaText: "",
    canStart: false,
    canStop: false,
    canPause: false
  };
  return {
    getSnapshot: () => snapshot,
    getPackageLogPath: () => null,
    getItemLogPath: () => null
  } as unknown as DownloadManager;
}

describe("buildSupportBundle (async, non-blocking)", () => {
  it("returns a Promise and produces a valid zip with overview + a real on-disk file", async () => {
    const root = fs.mkdtempSync(path.join(os.tmpdir(), "rd-bundle-"));
    tempDirs.push(root);
    fs.writeFileSync(path.join(root, "debug_host.txt"), "host-info-test", "utf8");
    fs.writeFileSync(path.join(root, "debug_support_manifest.json"), JSON.stringify({ purpose: "support" }), "utf8");
    fs.writeFileSync(path.join(root, legacyManifestFile), JSON.stringify({ purpose: "legacy" }), "utf8");

    const promise = buildSupportBundle(fakeManager(), root, { hostDiagnosticsMode: "none" });
    expect(promise).toBeInstanceOf(Promise);

    const buffer = await promise;
    expect(Buffer.isBuffer(buffer)).toBe(true);
    expect(buffer.length).toBeGreaterThan(0);

    const entries = new AdmZip(buffer).getEntries().map((e) => e.entryName);
    expect(entries).toContain("overview/meta.json");
    expect(entries).toContain("overview/settings.json");
    expect(entries).toContain("runtime/debug_host.txt");
    expect(entries).toContain("runtime/debug_support_manifest.json");
    expect(entries).toContain("overview/support-manifest.json");
    expect(entries).not.toContain(`runtime/${legacyManifestFile}`);
    expect(entries).not.toContain(["overview/", "a", "i-manifest.json"].join(""));

    const hostEntry = new AdmZip(buffer).getEntry("runtime/debug_host.txt");
    expect(hostEntry?.getData().toString("utf8")).toBe("host-info-test");
  });

  it("does not block the event loop while building (a concurrent timer still fires)", async () => {
    const root = fs.mkdtempSync(path.join(os.tmpdir(), "rd-bundle-"));
    tempDirs.push(root);

    let timerFired = false;
    const timer = setTimeout(() => { timerFired = true; }, 0);
    await buildSupportBundle(fakeManager(), root, { hostDiagnosticsMode: "none" });
    clearTimeout(timer);
    await new Promise((resolve) => setTimeout(resolve, 0));
    expect(timerFired).toBe(true);
  });
});
