#!/usr/bin/env node
import {
  CONFIG_FLAG_ARGS,
  defineCommand,
  findProjectCompiledResultsForRevision,
  getProjectCompiledResultSdk,
  parseConfigFlags,
  uploadInitialProjectionSdk
} from "./chunk-KDBSVLCF.mjs";
import {
  getProjectAuthoringState,
  getProjectCompileState,
  getProjectPendingAuthoringSync
} from "./chunk-YE7UAO3T.mjs";
import {
  generateReducerNativeArtifacts,
  isReducerNativeTestingWorkspace,
  runReducerNativeScenarios
} from "./chunk-ON62IGWK.mjs";
import "./chunk-XKCJBIRY.mjs";
import {
  STALE_CONTRACT_ARTIFACT_CODE,
  STALE_CONTRACT_ARTIFACT_EXIT_CODE,
  isDreamboardApiError,
  isStaleContractArtifactMessage
} from "./chunk-IDVQXGAO.mjs";
import {
  assertReleaseEnvironmentPortableDependencies,
  configureClient,
  consola,
  resolveProjectContext
} from "./chunk-JO5AMVZU.mjs";
import "./chunk-5NYBTZB4.mjs";
import "./chunk-27EEIZCI.mjs";
import "./chunk-F2DIOJJZ.mjs";
import {
  IS_PUBLISHED_BUILD
} from "./chunk-776W3UGV.mjs";
import "./chunk-C3VW3DTA.mjs";
import "./chunk-JZTH3EMV.mjs";
import "./chunk-QBAF7EYR.mjs";
import "./chunk-NAK77WXW.mjs";
import "./chunk-TAEQKBJB.mjs";
import "./chunk-IAYRNVUC.mjs";
import "./chunk-H76MT5UR.mjs";
import "./chunk-H6XDQJ3N.mjs";

// src/commands/test.ts
import { readFile } from "fs/promises";
import path from "path";

// src/services/testing/runtime-mode.ts
function isRemoteTestEnvironment(environment) {
  return environment === "staging" || environment === "prod";
}
function shouldUseRemoteTestRuntime(environment) {
  return IS_PUBLISHED_BUILD || isRemoteTestEnvironment(environment);
}

// src/services/workflows/resolve-latest-compiled-result.ts
async function resolveLatestCompiledResult(projectRoot, projectConfig) {
  void projectRoot;
  const authoring = getProjectAuthoringState(projectConfig);
  if (getProjectPendingAuthoringSync(projectConfig)) {
    throw new Error(
      "Previous sync did not finish updating local scaffold files. Run 'dreamboard sync' again first."
    );
  }
  if (authoring.revisionDigest) {
    const compile = getProjectCompileState(projectConfig);
    const latestSuccess = (await findProjectCompiledResultsForRevision({
      projectId: projectConfig.projectId,
      revisionDigest: authoring.revisionDigest
    })).find((result) => result.success);
    const matchingLocalSuccess = compile.latestSuccessful?.revisionDigest === authoring.revisionDigest ? compile.latestSuccessful : void 0;
    const resolvedSuccess = latestSuccess ?? (matchingLocalSuccess?.resultId ? await getProjectCompiledResultSdk(
      projectConfig.projectId,
      matchingLocalSuccess.resultId
    ) : void 0);
    if (!resolvedSuccess?.success) {
      throw new Error(
        "No successful compile exists for the current authored revision. Run 'dreamboard compile' first."
      );
    }
    const resultRevisionDigest = resolvedSuccess.revisionDigest;
    if (resultRevisionDigest && resultRevisionDigest !== authoring.revisionDigest) {
      consola.warn(
        `Latest successful compile ${resolvedSuccess.id} belongs to ${resultRevisionDigest}, not ${authoring.revisionDigest}.`
      );
    }
    consola.info(
      `Project summary:
  compiledResultId: ${resolvedSuccess.id}
  revisionDigest: ${authoring.revisionDigest}`
    );
    return resolvedSuccess;
  }
  throw new Error(
    "This workspace does not know its project revision yet. Run 'dreamboard sync' first."
  );
}

// src/commands/test.ts
var REDUCER_NATIVE_TEST_WORKSPACE_ERROR = "dreamboard test now requires a reducer-native workspace with app/game.ts, shared/generated/ui-contract.ts, test/bases/*.base.ts, and test/scenarios/*.scenario.ts. Legacy test/base-scenarios.json workspaces are no longer supported.";
var NO_REDUCER_NATIVE_BASES_FOUND_ERROR = "No bases found under test/bases/*.base.ts";
var NO_REDUCER_NATIVE_SCENARIOS_FOUND_ERROR = "No scenarios found under test/scenarios/*.scenario.ts";
function isPreviewProjectionEndpointUnavailable(error) {
  if (!isDreamboardApiError(error) || error.status !== 404) {
    return false;
  }
  const endpoint = error.problem.instance ?? error.problem.context?.endpoint;
  const message = error.problem.detail ?? error.problem.title;
  return endpoint?.includes("/preview/initial-projection") === true && message?.toLowerCase() === "not found";
}
async function uploadGeneratedPreviewProjection(options) {
  const previewBase = options.bases.find((base) => base.definition.id === "initial-turn") ?? options.bases[0];
  if (!previewBase) {
    return;
  }
  const projectionPath = path.join(
    options.projectRoot,
    "test",
    "generated",
    "bases",
    previewBase.definition.id,
    "player-1.projection.json"
  );
  const projectionJson = await readFile(projectionPath, "utf8");
  try {
    await uploadInitialProjectionSdk(options.gameId, projectionJson);
  } catch (error) {
    if (isPreviewProjectionEndpointUnavailable(error)) {
      consola.warn(
        "Skipping preview projection upload because the selected backend does not expose the preview projection endpoint."
      );
      return;
    }
    throw error;
  }
}
function resolveRequestedRunner(value) {
  if (value == null || value === "") {
    return void 0;
  }
  if (value === "reducer" || value === "remote" || value === "browser") {
    return value;
  }
  throw new Error(
    `Unsupported test runner '${String(value)}'. Expected one of reducer, remote, browser.`
  );
}
function isStaleContractArtifactResult(result) {
  return result.errorCode === STALE_CONTRACT_ARTIFACT_CODE || (result.error ? isStaleContractArtifactMessage(result.error) : false);
}
function resolveTestRunExitCode(summary) {
  if (summary.failed === 0) {
    return 0;
  }
  return summary.results.some(
    (result) => !result.success && isStaleContractArtifactResult(result)
  ) ? STALE_CONTRACT_ARTIFACT_EXIT_CODE : 1;
}
async function assertReducerNativeTestingWorkspace(projectRoot) {
  if (await isReducerNativeTestingWorkspace(projectRoot)) {
    return;
  }
  throw new Error(REDUCER_NATIVE_TEST_WORKSPACE_ERROR);
}
async function resolveReducerNativeRuntimeIdentity(options) {
  if (options.useRemoteRuntime || options.runner === "remote" || options.runner === "browser") {
    const latestCompiledResult = await resolveLatestCompiledResult(
      options.projectRoot,
      options.projectConfig
    );
    return {
      gameId: options.projectConfig.gameId,
      compiledResultId: latestCompiledResult.id
    };
  }
  return {
    gameId: options.projectConfig.gameId,
    compiledResultId: options.projectConfig.compile?.latestSuccessful?.resultId
  };
}
var generateCommand = defineCommand({
  meta: {
    name: "generate",
    description: "Generate reducer-native base artifacts for typed scenarios"
  },
  args: {
    scenario: {
      type: "string",
      description: "Optional scenario file path under test/scenarios"
    },
    debug: {
      type: "boolean",
      description: "Print full reducer-native validation details",
      default: false
    },
    "update-snapshots": {
      type: "boolean",
      description: "Refresh generated projection and scenario snapshots",
      default: false
    },
    ...CONFIG_FLAG_ARGS
  },
  async run({ args }) {
    const parsedFlags = parseConfigFlags(args);
    const useRemoteRuntime = shouldUseRemoteTestRuntime(parsedFlags.env);
    const { projectRoot, projectConfig, config } = await resolveProjectContext(
      parsedFlags,
      { requireAuth: useRemoteRuntime }
    );
    await assertReleaseEnvironmentPortableDependencies({
      projectRoot,
      projectConfig,
      environment: config.environment
    });
    await assertReducerNativeTestingWorkspace(projectRoot);
    const runtimeIdentity = await resolveReducerNativeRuntimeIdentity({
      projectRoot,
      projectConfig,
      useRemoteRuntime
    });
    const { bases, scenarios } = await generateReducerNativeArtifacts({
      projectRoot,
      scenarioPath: args.scenario,
      compiledResultId: runtimeIdentity.compiledResultId,
      gameId: runtimeIdentity.gameId,
      debug: Boolean(args.debug)
    });
    if (bases.length === 0) {
      throw new Error(NO_REDUCER_NATIVE_BASES_FOUND_ERROR);
    }
    if (scenarios.length === 0) {
      throw new Error(NO_REDUCER_NATIVE_SCENARIOS_FOUND_ERROR);
    }
    if (useRemoteRuntime && config.authToken) {
      await configureClient(config);
      await uploadGeneratedPreviewProjection({
        projectRoot,
        gameId: runtimeIdentity.gameId,
        bases
      });
    } else {
      consola.info(
        "Skipping preview projection upload because this test generation is local-only."
      );
    }
    consola.success(
      `Generated ${bases.length} base state(s) for ${scenarios.length} scenario(s).`
    );
  }
});
var runCommand = defineCommand({
  meta: {
    name: "run",
    description: "Run reducer-native scenarios from test/scenarios"
  },
  args: {
    scenario: {
      type: "string",
      description: "Optional scenario file path under test/scenarios"
    },
    debug: {
      type: "boolean",
      description: "Print full reducer-native validation details",
      default: false
    },
    "update-snapshots": {
      type: "boolean",
      description: "Refresh generated projection and scenario snapshots",
      default: false
    },
    runner: {
      type: "string",
      valueHint: "reducer|remote|browser",
      description: "Scenario runner: reducer (in-process, default), remote (live sessions against the configured backend), or browser (local web stack)."
    },
    ...CONFIG_FLAG_ARGS
  },
  async run({ args }) {
    const parsedFlags = parseConfigFlags(args);
    const useRemoteRuntime = shouldUseRemoteTestRuntime(parsedFlags.env);
    const runner = resolveRequestedRunner(args.runner) ?? "reducer";
    const { projectRoot, projectConfig, config } = await resolveProjectContext(
      parsedFlags,
      {
        requireAuth: useRemoteRuntime || runner === "remote" || runner === "browser"
      }
    );
    await assertReleaseEnvironmentPortableDependencies({
      projectRoot,
      projectConfig,
      environment: config.environment
    });
    await assertReducerNativeTestingWorkspace(projectRoot);
    const runtimeIdentity = await resolveReducerNativeRuntimeIdentity({
      projectRoot,
      projectConfig,
      useRemoteRuntime,
      runner
    });
    const summary = await runReducerNativeScenarios({
      projectRoot,
      projectConfig,
      resolvedConfig: config,
      runner,
      scenarioPath: args.scenario,
      compiledResultId: runtimeIdentity.compiledResultId,
      gameId: runtimeIdentity.gameId,
      debug: Boolean(args.debug),
      updateSnapshots: Boolean(args["update-snapshots"])
    });
    for (const result of summary.results) {
      if (result.success) {
        consola.success(`PASS ${result.id}`);
      } else if (result.errorCode === STALE_CONTRACT_ARTIFACT_CODE && result.error) {
        consola.error(result.error);
      } else {
        consola.error(
          `FAIL ${result.id}: ${result.error ?? "Scenario failed"}`
        );
      }
    }
    consola.info(
      `Test summary: ${summary.passed} passed, ${summary.failed} failed.`
    );
    if (summary.failed > 0) {
      process.exitCode = resolveTestRunExitCode(summary);
    }
  }
});
var test_default = defineCommand({
  meta: {
    name: "test",
    description: "Reducer-native test runner with typed bases and scenarios"
  },
  subCommands: {
    generate: generateCommand,
    run: runCommand
  }
});
export {
  NO_REDUCER_NATIVE_BASES_FOUND_ERROR,
  NO_REDUCER_NATIVE_SCENARIOS_FOUND_ERROR,
  REDUCER_NATIVE_TEST_WORKSPACE_ERROR,
  test_default as default,
  isPreviewProjectionEndpointUnavailable,
  resolveRequestedRunner,
  resolveTestRunExitCode
};
//# sourceMappingURL=test-Y5UGQV7J.mjs.map