import { readdirSync, readFileSync } from "node:fs";
import { resolve } from "node:path";
import { describe, expect, it } from "vitest";

const repoRoot = resolve(import.meta.dirname, "../../..");

function listVendoredSourceFiles(directory: string): string[] {
  const entries = readdirSync(directory, { withFileTypes: true });
  const files: string[] = [];
  for (const entry of entries) {
    const entryPath = resolve(directory, entry.name);
    if (entry.isDirectory()) {
      files.push(...listVendoredSourceFiles(entryPath));
      continue;
    }
    if (entry.isFile() && /\.(ts|tsx)$/.test(entry.name)) {
      files.push(entryPath);
    }
  }
  return files;
}

describe("owned dimsdk entrypoints", () => {
  it("loads the vendored dimsdk source instead of node_modules/dimcode", () => {
    const entry = readFileSync(resolve(repoRoot, "scripts/dimsdk-tui.ts"), "utf8");
    expect(entry).toContain("../apps/cli/src/dimsdk/cli/terminal.ts");
    expect(entry).toContain("../apps/cli/src/dimsdk/index.ts");
    expect(entry).not.toContain("node_modules/dimcode");
  });

  it("does not keep dimcode as a root dependency", () => {
    const packageJson = readFileSync(resolve(repoRoot, "package.json"), "utf8");
    expect(packageJson).not.toContain("\"dimcode\"");
  });

  it("does not keep machine-specific goatagent links as root dependencies", () => {
    const packageJson = readFileSync(resolve(repoRoot, "package.json"), "utf8");
    expect(packageJson).not.toContain("link:/Users/Simon/Github/goatagent/");
  });

  it("does not keep @archships imports in the vendored dimsdk sources", () => {
    const sourceFiles = listVendoredSourceFiles(
      resolve(repoRoot, "apps/cli/src/dimsdk"),
    );
    expect(sourceFiles.length).toBeGreaterThan(0);
    for (const file of sourceFiles) {
      const source = readFileSync(file, "utf8");
      expect(source, file).not.toContain("@archships/");
    }
  });

  it("keeps the VoiceInput Swift package aligned with the VoiceIn target", () => {
    const packageManifest = readFileSync(
      resolve(repoRoot, "VoiceInputMenuBarApp/Package.swift"),
      "utf8",
    );
    expect(packageManifest).toContain('name: "VoiceIn"');
    expect(packageManifest).toContain('targets: ["VoiceIn"]');
    expect(packageManifest).toContain('path: "Sources/VoiceIn"');

    const sourceRoot = resolve(repoRoot, "VoiceInputMenuBarApp/Sources");
    const sourceEntries = readdirSync(sourceRoot, { withFileTypes: true });
    const sourceFiles = sourceEntries.flatMap((entry) => {
      if (!entry.isDirectory()) {
        return [];
      }
      const entryRoot = resolve(sourceRoot, entry.name);
      return readdirSync(entryRoot, { withFileTypes: true })
        .filter((child) => child.isFile())
        .map((child) => `${entry.name}/${child.name}`);
    }).sort();

    expect(sourceFiles).toEqual(["VoiceIn/main.swift"]);
  });

  it("keeps compat entrypoints as thin alias wrappers", () => {
    const compatRoot = resolve(repoRoot, "apps/cli/src/dimsdk/compat");
    const compatFiles = readdirSync(compatRoot, { withFileTypes: true })
      .filter((entry) => entry.isFile() && entry.name.endsWith(".ts"))
      .map((entry) => entry.name)
      .sort();

    expect(compatFiles).toEqual([
      "config.ts",
      "mcp.ts",
      "plugin-api.ts",
      "providers.ts",
      "runtime-host.ts",
      "runtime.ts",
    ]);

    expect(readFileSync(resolve(compatRoot, "config.ts"), "utf8").trim()).toBe(
      "export * from './archships/dim-agent/config'",
    );
    expect(readFileSync(resolve(compatRoot, "mcp.ts"), "utf8").trim()).toBe(
      "export * from './archships/dim-agent/mcp'",
    );
    expect(readFileSync(resolve(compatRoot, "plugin-api.ts"), "utf8").trim()).toBe(
      "export * from './archships/dim-plugin-api'",
    );
    expect(readFileSync(resolve(compatRoot, "providers.ts"), "utf8").trim()).toBe(
      "export * from './archships/dim-agent/providers'",
    );
    expect(readFileSync(resolve(compatRoot, "runtime-host.ts"), "utf8").trim()).toBe(
      "export * from './archships/dim-agent/runtime-host'",
    );
    expect(readFileSync(resolve(compatRoot, "runtime.ts"), "utf8").trim()).toBe(
      "export * from './archships/dim-agent/runtime'",
    );
  });

  it("does not bypass compat entrypoints from dimsdk production source", () => {
    const sourceFiles = listVendoredSourceFiles(resolve(repoRoot, "apps/cli/src/dimsdk")).filter(
      (file) =>
        !file.includes("/compat/") &&
        !file.endsWith(".test.ts"),
    );

    for (const file of sourceFiles) {
      const source = readFileSync(file, "utf8");
      expect(source, file).not.toContain("compat/archships/");
      expect(source, file).not.toContain("archships/dim-agent/");
      expect(source, file).not.toContain("archships/dim-plugin-api");
    }
  });
});
