import { execFileSync, spawnSync } from "node:child_process";
import { existsSync, mkdtempSync, writeFileSync } from "node:fs";
import { readFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import path from "node:path";
import { describe, expect, it } from "vitest";

const rootDir = path.resolve(__dirname, "../..");

function runScript(script: string, args: string[]) {
  return execFileSync("bash", [path.join(rootDir, script), ...args], {
    cwd: rootDir,
    encoding: "utf8",
    env: {
      ...process.env,
      CI: "1",
    },
  });
}

function runScriptResult(script: string, args: string[]) {
  return spawnSync("bash", [path.join(rootDir, script), ...args], {
    cwd: rootDir,
    encoding: "utf8",
    env: {
      ...process.env,
      CI: "1",
    },
  });
}

async function expectedPnpmVersion() {
  const packageJson = JSON.parse(await readFile(path.join(rootDir, "package.json"), "utf8"));
  const packageManager = String(packageJson.packageManager ?? "");
  return packageManager.replace(/^pnpm@/, "").split("+")[0];
}

describe("customer deployment scripts", () => {
  it("install dry-run reports dependency bootstrap, env preservation, and dev install steps", async () => {
    const tempDir = mkdtempSync(path.join(tmpdir(), "customer-install-"));
    const envFile = path.join(tempDir, ".env");
    writeFileSync(envFile, "LLM_API_KEY=super-secret\n");

    const output = runScript("scripts/install.sh", [
      "--dry-run",
      "--no-start",
      "--with-python",
      "--env-file",
      envFile,
    ]);

    expect(output).toContain(`pnpm ${await expectedPnpmVersion()}`);
    expect(output).toContain("uv + Python 3.13");
    expect(output).toMatch(/(?:\.env already exists; keeping the existing file\.|copy env file to \.env)/);
    expect(output).toContain("pnpm install --frozen-lockfile");
    expect(output).not.toContain("super-secret");
  });

  it("delivery bundle dry-run injects env only into the delivery tag artifact plan without leaking values", () => {
    const tempDir = mkdtempSync(path.join(tmpdir(), "customer-bundle-"));
    const envFile = path.join(tempDir, ".env");
    writeFileSync(envFile, "LLM_API_KEY=super-secret\n");

    const output = runScript("scripts/build-delivery-bundle.sh", [
      "--dry-run",
      "--env-file",
      envFile,
      "--output-dir",
      tempDir,
      "--tag",
      "v2099.01.01-test",
    ]);

    expect(output).toContain("deploy/env/.env");
    expect(output).toContain(".delivery.tar.gz");
    expect(output).toContain("1688-autoprocurement-pulse-v2099.01.01-test.delivery.tar.gz");
    expect(output).toContain("MANIFEST.txt");
    expect(output).toContain("delivery tag v2099.01.01-test");
    expect(output).not.toContain("super-secret");
  });

  it("delivery bundle rejects source overrides", () => {
    const tempDir = mkdtempSync(path.join(tmpdir(), "customer-bundle-default-"));
    const envFile = path.join(tempDir, ".env");
    writeFileSync(envFile, "LLM_API_KEY=super-secret\n");

    const result = runScriptResult("scripts/build-delivery-bundle.sh", [
      "--env-file",
      envFile,
      "--output-dir",
      tempDir,
      "--ref",
      "HEAD",
    ]);

    expect(result.status).not.toBe(0);
    expect(result.stderr).toContain("delivery repository tags");
    expect(result.stderr).not.toContain("super-secret");
  });

  it("delivery bundle can be run through pnpm", () => {
    const packageJson = JSON.parse(execFileSync("cat", [path.join(rootDir, "package.json")], { encoding: "utf8" }));

    expect(packageJson.scripts["build:delivery-bundle"]).toBe("bash scripts/build-delivery-bundle.sh");
  });

  it("delivery bundle uses the requested delivery tag snapshot shape", () => {
    const tempDir = mkdtempSync(path.join(tmpdir(), "customer-bundle-snapshot-"));
    const envFile = path.join(tempDir, ".env");
    writeFileSync(envFile, "LLM_API_KEY=super-secret\n");
    const sourceCommit = execFileSync("git", ["-C", rootDir, "rev-parse", "origin/main^{commit}"], {
      encoding: "utf8",
    }).trim();
    const tagName = `bundle-test-${Date.now()}`;
    execFileSync("git", ["-C", rootDir, "tag", tagName, sourceCommit]);

    try {
      runScript("scripts/build-delivery-bundle.sh", [
        "--env-file",
        envFile,
        "--output-dir",
        tempDir,
        "--tag",
        tagName,
        "--no-fetch",
      ]);

      const bundlePath = execFileSync("bash", ["-lc", `ls ${JSON.stringify(tempDir)}/*.delivery.tar.gz`], {
        encoding: "utf8",
      }).trim();
      expect(path.basename(bundlePath)).toContain(`${tagName}-`);
      const extractDir = path.join(tempDir, "extract");
      execFileSync("mkdir", ["-p", extractDir]);
      execFileSync("tar", ["-xzf", bundlePath, "-C", extractDir]);

      expect(existsSync(path.join(extractDir, "deploy/env/.env"))).toBe(true);
      const manifest = execFileSync("cat", [path.join(extractDir, "MANIFEST.txt")], { encoding: "utf8" });
      expect(manifest).toContain(`artifact_name=${path.basename(bundlePath)}`);
      expect(manifest).toContain(`delivery_tag=${tagName}`);
    } finally {
      execFileSync("git", ["-C", rootDir, "tag", "-d", tagName], { stdio: "ignore" });
    }
  });

  it("publish delivery dry-run keeps origin main fixed and plans the automatic bundle", () => {
    const tempDir = mkdtempSync(path.join(tmpdir(), "publish-bundle-"));
    const envFile = path.join(tempDir, ".env");
    writeFileSync(envFile, "LLM_API_KEY=super-secret\n");

    const output = runScript("scripts/publish-delivery.sh", [
      "--dry-run",
      "--no-fetch",
      "--delivery-tag",
      "v2099.01.01-test",
      "--bundle-env-file",
      envFile,
      "--bundle-output-dir",
      tempDir,
    ]);

    expect(output).toContain("source:  origin/main");
    expect(output).toContain("开发库 tag: v2099.01.01-test -> origin/main");
    expect(output).toContain("交付 tag: v2099.01.01-test");
    expect(output).toContain("自动生成客户交付包");
    expect(output).toContain("delivery tag v2099.01.01-test");
    expect(output).toContain("1688-autoprocurement-pulse-v2099.01.01-test.delivery.tar.gz");
    expect(output).not.toContain("super-secret");
  });

  it("publish delivery requires a delivery tag", () => {
    const result = runScriptResult("scripts/publish-delivery.sh", ["--dry-run", "--no-fetch"]);

    expect(result.status).not.toBe(0);
    expect(result.stderr).toContain("--delivery-tag");
  });

  it("publish delivery rejects source ref overrides", () => {
    const result = runScriptResult("scripts/publish-delivery.sh", ["--ref", "HEAD"]);

    expect(result.status).not.toBe(0);
    expect(result.stderr).toContain("origin/main");
  });

  it("publish delivery does not allow disabling bundle generation", () => {
    const result = runScriptResult("scripts/publish-delivery.sh", ["--no-bundle"]);

    expect(result.status).not.toBe(0);
    expect(result.stderr).toContain("必须自动调用 scripts/build-delivery-bundle.sh");
  });
});
