import { type BuildSettings, resolveBuildSettings } from "./build-settings.ts";
import type { BuildArtifact, BuildStrategy } from "./build-strategy.ts";
import {
  hasPackageDependency,
  runBuildSettingsCommand,
} from "./build-strategy.ts";
import { stageConfiguredArtifact } from "./configured-artifact.ts";
import type { BuildCommandIo } from "./workspace.ts";

const TANSTACK_START_PACKAGES = [
  "@tanstack/react-start",
  "@tanstack/solid-start",
];

/**
 * Build strategy for TanStack Start applications targeting the Nitro node
 * preset. Runs the resolved build command (the user's `package.json` build
 * script, or `vite build`) and produces an artifact from its output directory.
 */
export class TanstackStartBuild implements BuildStrategy {
  readonly #appPath: string;
  readonly #buildSettings?: BuildSettings;
  readonly #io?: BuildCommandIo;

  constructor(options: {
    appPath: string;
    buildSettings?: BuildSettings;
    io?: BuildCommandIo;
  }) {
    this.#appPath = options.appPath;
    this.#buildSettings = options.buildSettings;
    this.#io = options.io;
  }

  async canBuild(signal?: AbortSignal): Promise<boolean> {
    return hasPackageDependency(this.#appPath, TANSTACK_START_PACKAGES, signal);
  }

  async execute(signal?: AbortSignal): Promise<BuildArtifact> {
    signal?.throwIfAborted();
    const settings =
      this.#buildSettings ??
      (await resolveBuildSettings({
        appPath: this.#appPath,
        buildType: "tanstack-start",
        signal,
      }));
    await runBuildSettingsCommand({
      appPath: this.#appPath,
      settings,
      failurePrefix: "TanStack Start",
      defaultCli: {
        source: "TanStack Start default",
        cliName: "vite",
        args: ["build"],
        missingMessage:
          "Could not find the Vite CLI. Install it with `npm install vite` or ensure npx/bunx is available.",
      },
      io: this.#io,
      signal,
    });

    return stageConfiguredArtifact({
      appPath: this.#appPath,
      outputDirectory: settings.outputDirectory,
      entrypoint: settings.entrypoint ?? "server/index.mjs",
      buildType: "tanstack-start",
      label: "TanStack Start",
      missingEntrypointMessage: settings.entrypoint
        ? undefined
        : `TanStack Start build did not produce a Nitro node server entrypoint at ${settings.outputDirectory}/server/index.mjs. Ensure your vite.config includes the tanstackStart() and nitro() plugins with the default node preset.`,
      signal,
    });
  }
}
