import { expect, test } from "bun:test";
import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { format } from "prettier";
import { scaffoldApp } from "../src/create.ts";
import { currentCliVersion } from "../src/update-notifier.ts";

test("scaffoldApp creates a comprehensive .gitignore", () => {
  const parent = mkdtempSync(join(tmpdir(), "wrnexus-create-"));
  const root = join(parent, "demo-app");

  try {
    scaffoldApp(root, "demo-app");

    const file = join(root, ".gitignore");
    expect(existsSync(file)).toBe(true);
    const contents = readFileSync(file, "utf8");
    for (const entry of [
      "node_modules/",
      "dist/",
      ".wrnexus/",
      ".env.*",
      "!.env.example",
      "*.log",
      "*.db",
      "coverage/",
      "mobile/android/",
      ".vscode/",
      "*.tsbuildinfo",
    ]) {
      expect(contents).toContain(entry);
    }
  } finally {
    rmSync(parent, { recursive: true, force: true });
  }
});

test("scaffoldApp includes production build and start scripts", () => {
  const parent = mkdtempSync(join(tmpdir(), "wrnexus-create-"));
  const root = join(parent, "production-app");

  try {
    scaffoldApp(root, "production-app");
    const pkg = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));

    expect(pkg.scripts.build).toBe("wrnexus build .");
    expect(pkg.scripts.start).toBe("bun dist/server.js");
    expect(pkg.scripts.production).toBe("bun run build && bun run start");
  } finally {
    rmSync(parent, { recursive: true, force: true });
  }
});

test("scaffoldApp pins the current framework and exposes llms.txt publicly", () => {
  const parent = mkdtempSync(join(tmpdir(), "wrnexus-create-"));
  const root = join(parent, "current-app");

  try {
    scaffoldApp(root, "current-app");
    const pkg = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
    const version = currentCliVersion();

    expect(pkg.wrnexus.version).toBe(version);
    expect(pkg.dependencies["@wrnexus/helpers"]).toBe(version);
    for (const dependency of Object.values(pkg.dependencies) as string[]) {
      expect(dependency).toBe(version);
    }
    expect(pkg.devDependencies["@wrnexus/cli"]).toBe(version);
    expect(existsSync(join(root, "public", "llms.txt"))).toBe(true);
    expect(existsSync(join(root, "llms.txt"))).toBe(false);
    expect(readFileSync(join(root, ".prettierignore"), "utf8")).toContain("CLAUDE.md");
    expect(readFileSync(join(root, ".vscode", "settings.json"), "utf8")).toContain(
      '"editor.formatOnSave": true',
    );
    expect(readFileSync(join(root, ".vscode", "settings.json"), "utf8")).toContain(
      '"editor.defaultFormatter": "wrnexus.wrnexus"',
    );
    expect(readFileSync(join(root, ".vscode", "extensions.json"), "utf8")).toContain(
      "wrnexus.wrnexus",
    );
    expect(readFileSync(join(root, "app", "pages", "index.wrn"), "utf8")).toContain(
      'href="/api/hello"',
    );
    expect(existsSync(join(root, "app", "pages", "about.wrn"))).toBe(true);
  } finally {
    rmSync(parent, { recursive: true, force: true });
  }
});

test("scaffoldApp emits Prettier-compliant editor and framework files", async () => {
  const parent = mkdtempSync(join(tmpdir(), "wrnexus-create-"));
  const root = join(parent, "formatted-app");

  try {
    scaffoldApp(root, "formatted-app");
    for (const relative of [
      "app/styles/global.css",
      "eslint.config.js",
      ".vscode/settings.json",
      ".vscode/extensions.json",
    ]) {
      const file = join(root, relative);
      const source = readFileSync(file, "utf8");
      const formatted = await format(source, {
        filepath: file,
        printWidth: 100,
        tabWidth: 2,
        useTabs: false,
        semi: true,
        singleQuote: false,
        trailingComma: "all",
        endOfLine: "lf",
      });
      expect(formatted).toBe(source);
    }
  } finally {
    rmSync(parent, { recursive: true, force: true });
  }
});
