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

/**
 * Generic artifact strategy for frameworks the SDK does not know about yet.
 * Runs an optional command, stages a configured output directory as-is, and
 * starts the configured entrypoint from inside that artifact.
 */
export class CustomBuild implements BuildStrategy {
  readonly #appPath: string;
  readonly #entrypoint?: string;
  readonly #buildSettings?: BuildSettings;
  readonly #io?: BuildCommandIo;

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

  async canBuild(_signal?: AbortSignal): Promise<boolean> {
    return Boolean(this.#entrypoint ?? this.#buildSettings?.entrypoint);
  }

  async execute(signal?: AbortSignal): Promise<BuildArtifact> {
    signal?.throwIfAborted();
    const settings =
      this.#buildSettings ??
      (await resolveBuildSettings({
        appPath: this.#appPath,
        buildType: "custom",
        signal,
      }));

    const entrypoint = this.#entrypoint ?? settings.entrypoint;
    if (!entrypoint) {
      throw new Error("Custom build entrypoint is required");
    }
    normalizeConfiguredArtifactEntrypoint(entrypoint, "Custom");

    await runBuildSettingsCommand({
      appPath: this.#appPath,
      settings,
      failurePrefix: "Custom",
      io: this.#io,
      signal,
    });

    return stageConfiguredArtifact({
      appPath: this.#appPath,
      outputDirectory: settings.outputDirectory,
      entrypoint,
      buildType: "custom",
      label: "Custom",
      signal,
    });
  }
}
