import { scheduleRetryRunObservation, scheduleRunObservation, scheduleRunsScope } from "./src/schedules";
import { backendCoreUnavailableDiagnostic } from "./src/microservices";

type JsonRecord = Record<string, unknown>;

function assertCondition(condition: unknown, message: string, detail: JsonRecord = {}): void {
  if (!condition) throw new Error(`${message}: ${JSON.stringify(detail)}`);
}

export function runScheduleCliContract(): JsonRecord {
  const global = scheduleRunsScope(["runs", "--limit", "50"]);
  assertCondition(global.scheduleId === null, "global schedule runs must not treat --limit value as schedule id", global);
  assertCondition(global.limit === 50, "global schedule runs limit should be preserved", global);

  const scoped = scheduleRunsScope(["runs", "unidesk-pgdata-baidu-daily", "--limit", "5"]);
  assertCondition(scoped.scheduleId === "unidesk-pgdata-baidu-daily", "schedule-specific runs should preserve schedule id", scoped);
  assertCondition(scoped.limit === 5, "schedule-specific runs limit should be preserved", scoped);

  let numericScheduleRejected = false;
  try {
    scheduleRunsScope(["runs", "50"]);
  } catch (error) {
    numericScheduleRejected = String((error as Error).message).includes("schedule runs --limit N");
  }
  assertCondition(numericScheduleRejected, "numeric positional schedule id should point operators to global --limit syntax");

  const timeoutObservation = scheduleRunObservation(
    "unidesk-pgdata-baidu-daily",
    { body: { run: { id: "schedrun_new" } } },
    { ok: false, timedOut: true, timeoutMs: 1 },
  );
  assertCondition(timeoutObservation.newRunId === "schedrun_new", "schedule run output must expose newRunId even when wait times out", timeoutObservation);
  assertCondition(String(timeoutObservation.observeCommand).includes("schedule runs unidesk-pgdata-baidu-daily --limit 20"), "schedule run output must expose observeCommand", timeoutObservation);

  const retryObservation = scheduleRetryRunObservation("schedrun_failed", {
    body: {
      originalRunId: "schedrun_failed",
      scheduleId: "unidesk-pgdata-baidu-daily",
      newRunId: "schedrun_retry",
    },
  });
  assertCondition(retryObservation.originalRunId === "schedrun_failed", "retry-run output must preserve originalRunId", retryObservation);
  assertCondition(retryObservation.scheduleId === "unidesk-pgdata-baidu-daily", "retry-run output must expose scheduleId", retryObservation);
  assertCondition(retryObservation.newRunId === "schedrun_retry", "retry-run output must expose newRunId", retryObservation);
  assertCondition(String(retryObservation.observeCommand).includes("schedule runs unidesk-pgdata-baidu-daily --limit 20"), "retry-run output must expose observeCommand", retryObservation);

  const unavailable = backendCoreUnavailableDiagnostic({
    exitCode: 1,
    stdoutTail: "",
    stderrTail: "Error response from daemon: No such container: unidesk-backend-core\n",
    relatedContainers: [
      { name: "unidesk-backend-core.verify-20260520T153456Z", image: "unidesk-backend-core:latest", status: "Exited (255)" },
      { name: "unidesk-database.verify-20260520T153456Z", image: "postgres:16-alpine", status: "Exited (255)" },
    ],
    envPath: "/tmp/docker-compose.env",
    baiduSecretPresence: {
      envPath: "/tmp/docker-compose.env",
      exists: true,
      keys: {
        UNIDESK_BAIDU_NETDISK_CLIENT_ID: { present: true, nonEmpty: false },
        UNIDESK_BAIDU_NETDISK_CLIENT_SECRET: { present: true, nonEmpty: false },
        UNIDESK_BAIDU_NETDISK_TOKEN_KEY: { present: true, nonEmpty: false },
      },
    },
  });
  assertCondition(unavailable.ok === false, "backend-core unavailable diagnostic must be a failed result", unavailable);
  assertCondition(unavailable.failureKind === "target-stack-not-running", "backend-core unavailable diagnostic must classify target stack absence", unavailable);
  assertCondition((unavailable.targetStack as JsonRecord).verifyOnlyObserved === true, "backend-core unavailable diagnostic must expose verify-only evidence", unavailable);
  assertCondition(Array.isArray(unavailable.authorizationRequiredForRecovery), "backend-core unavailable diagnostic must list authorization-gated recovery actions", unavailable);
  assertCondition(Array.isArray(unavailable.readOnlyCommands), "backend-core unavailable diagnostic must list read-only observation commands", unavailable);

  return {
    ok: true,
    checks: [
      "global schedule runs limit parsing",
      "schedule-specific runs parsing",
      "numeric positional guard",
      "run wait timeout observation",
      "retry-run observation",
      "target stack unavailable diagnostic",
    ],
  };
}

if (import.meta.main) {
  process.stdout.write(`${JSON.stringify(runScheduleCliContract(), null, 2)}\n`);
}
