import { expect, test } from "bun:test";
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { currentCliVersion } from "../src/update-notifier.ts";
import {
  addWorkspaceApp,
  insertWorkspaceApp,
  resolveWorkspaceConfig,
  workspaceFiles,
  workspaceMigrationTargets,
} from "../src/workspace.ts";

test("workspace environments preserve runtime and HMR policy", () => {
  const resolved = resolveWorkspaceConfig(
    {
      environments: {
        staging: {
          protocol: "https",
          rootDomain: "staging.example.com",
          port: 443,
          runtime: "development",
          hmr: false,
          build: false,
          migrate: false,
          profile: "uat",
        },
      },
      apps: [{ name: "web", dir: "apps/web", subdomain: "www" }],
    },
    "staging",
  );
  expect(resolved.config.runtime).toBe("development");
  expect(resolved.config.hmr).toBe(false);
  expect(resolved.config.profile).toBe("uat");
  expect(resolved.apps[0]?.publicOrigin).toBe("https://www.staging.example.com");
});

test("workspace templates pin the running framework release", () => {
  const files = workspaceFiles("acme");
  const rootPackage = JSON.parse(files["package.json"]!);
  const sharedPackage = JSON.parse(files["packages/shared/package.json"]!);
  const version = currentCliVersion();

  expect(rootPackage.devDependencies["@wrnexus/cli"]).toBe(version);
  expect(sharedPackage.dependencies["@wrnexus/pubsub"]).toBe(version);
  expect(files["README.md"]).toContain("http://127.0.0.1:3000");
  expect(files["README.md"]).toContain("internal gateway targets");
  expect(JSON.parse(files["package.json"]!).scripts.production).toBe("wrnexus production");
  expect(JSON.parse(files["package.json"]!).scripts.check).toContain("typecheck");
  expect(JSON.parse(files["package.json"]!).scripts.check).toContain("format:check");
  expect(files["wrnexus.workspace.ts"]).toContain('runtime: "development"');
  expect(files["wrnexus.workspace.ts"]).toContain("hmr: false");
  expect(files[".env.example"]).toContain("REDIS_URL");
  expect(files["eslint.config.js"]).toContain("typescript-eslint");
  expect(files["tsconfig.json"]).toContain('"strict": true');
  expect(files[".vscode/extensions.json"]).toContain("wrnexus.wrnexus");
});

test("production workspace detects default and named SQL migrations", () => {
  const root = mkdtempSync(join(tmpdir(), "wrnexus-production-migrations-"));
  try {
    mkdirSync(join(root, "app", "db", "migrations"), { recursive: true });
    mkdirSync(join(root, "app", "db", "analytics", "migrations"), { recursive: true });
    mkdirSync(join(root, "app", "db", "empty", "migrations"), { recursive: true });
    writeFileSync(join(root, "app", "db", "migrations", "0001_init.sql"), "select 1;");
    writeFileSync(join(root, "app", "db", "analytics", "migrations", "0001_init.sql"), "select 1;");
    expect(workspaceMigrationTargets(root)).toEqual([null, "analytics"]);
  } finally {
    rmSync(root, { recursive: true, force: true });
  }
});

test("insertWorkspaceApp handles nested arrays and comments", () => {
  const source = `const config = {
  apps: [
    { name: "web", dir: "apps/web", domains: ["localhost"] },
    { name: "admin", dir: "apps/admin", domains: ["admin.localhost"], auth: { allowIps: ["::1"] } }, // ]
  ],
};
export default config;
`;
  const result = insertWorkspaceApp(source, {
    name: "reports",
    dir: "apps/reports",
    domains: ["reports.localhost"],
  });

  expect(result).toContain(
    '{ name: "reports", dir: "apps/reports", domains: ["reports.localhost"] },',
  );
  expect(result.indexOf('name: "reports"')).toBeLessThan(result.indexOf("\n  ],"));
});

test("workspace add scaffolds and registers an app", async () => {
  const root = mkdtempSync(join(tmpdir(), "wrnexus-workspace-add-"));
  writeFileSync(
    join(root, "wrnexus.workspace.ts"),
    'export default { apps: [{ name: "web", dir: "apps/web", domains: ["localhost"] }] };\n',
  );

  try {
    await addWorkspaceApp(root, "reports", ["--domain=reports.localhost"]);
    const manifest = JSON.parse(
      readFileSync(join(root, "apps", "reports", "package.json"), "utf8"),
    );
    const config = readFileSync(join(root, "wrnexus.workspace.ts"), "utf8");

    expect(manifest.name).toBe("reports");
    expect(manifest.wrnexus.version).toBe(currentCliVersion());
    expect(config).toContain('name: "reports"');
    expect(config).toContain('domains: ["reports.localhost"]');
    expect(existsSync(join(root, "apps", "reports", "public", "llms.txt"))).toBe(true);
  } finally {
    rmSync(root, { recursive: true, force: true });
  }
});
