// SPEC: PJ2026-01060307 控制面模块化 draft-2026-06-25-p0. types module for scripts/src/hwlab-g14.ts.

// Moved mechanically from scripts/src/hwlab-g14.ts:1-288 for #903.

import { chmodSync, existsSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { createHash, randomBytes } from "node:crypto";
import { repoRoot, rootPath, type Config } from "../config";
import { runCommand } from "../command";
import { cancelJob, listJobs, readJob, startJob } from "../jobs";
import { hwlabRequiredNoProxyEntries, hwlabRuntimeLaneConfigPath, hwlabRuntimeLaneIds, hwlabRuntimeLaneSpec, isHwlabRuntimeLane, type HwlabRuntimeLane, type HwlabRuntimeLaneSpec } from "../hwlab-node-lanes";

import { durationSeconds } from "./pr-monitor";

export const HWLAB_REPO = "pikasTech/HWLAB";

export const G14_SOURCE_BRANCH = "G14";

export const G14_PROVIDER = "G14";

export const G14_WORKSPACE = "/root/hwlab";

export const V02_LANE_SPEC = hwlabRuntimeLaneSpec("v02");

export const V02_SOURCE_BRANCH = V02_LANE_SPEC.sourceBranch;

export const V02_WORKSPACE = V02_LANE_SPEC.workspace;

export const V02_CICD_REPO = V02_LANE_SPEC.cicdRepo;

export const DEV_NAMESPACE = "hwlab-dev";

export const PROD_NAMESPACE = "hwlab-prod";

export const CI_NAMESPACE = "hwlab-ci";

export const ARGO_NAMESPACE = "argocd";

export const DEV_APP = "hwlab-g14-dev";

export const PROD_APP = "hwlab-g14-prod";

export const V02_APP = V02_LANE_SPEC.app;

export const V02_PIPELINE = V02_LANE_SPEC.pipeline;

export const V02_POLLER = "hwlab-v02-branch-poller";

export const V02_RECONCILER = "hwlab-v02-control-plane-reconciler";

export const V02_PIPELINERUN_PREFIX = V02_LANE_SPEC.pipelineRunPrefix;

export const V02_CONTROL_PLANE_FIELD_MANAGER = V02_LANE_SPEC.controlPlaneFieldManager;

export const V02_GIT_URL = V02_LANE_SPEC.gitUrl;

export const V02_GIT_READ_URL = V02_LANE_SPEC.gitReadUrl;

export const V02_GIT_WRITE_URL = V02_LANE_SPEC.gitWriteUrl;

export const V02_GITOPS_BRANCH = V02_LANE_SPEC.gitopsBranch;

export const V02_CATALOG_PATH = V02_LANE_SPEC.catalogPath;

export const V02_RUNTIME_PATH = V02_LANE_SPEC.runtimePath;

export const V02_RUNTIME_NAMESPACE = V02_LANE_SPEC.runtimeNamespace;

export const V02_OPENFGA_SECRET = "hwlab-v02-openfga";

export const V02_OPENFGA_AUTHN_SECRET_KEY = "authn-preshared-key";

export const V02_OPENFGA_DATASTORE_URI_SECRET_KEY = "datastore-uri";

export const V02_OPENFGA_POSTGRES_PASSWORD_SECRET_KEY = "postgres-password";

export const V02_OPENFGA_DB_NAME = "hwlab_openfga";

export const V02_OPENFGA_DB_USER = "hwlab_openfga";

export const V02_MASTER_ADMIN_API_KEY_SECRET = "hwlab-v02-master-server-admin-api-key";

export const V02_MASTER_ADMIN_API_KEY_SECRET_KEY = "api-key";

export const V02_MASTER_ADMIN_API_KEY_LOCAL_ENV = "/root/.config/hwlab-v02/master-server-admin-api-key.env";

export const V02_REGISTRY_PREFIX = V02_LANE_SPEC.registryPrefix;

export const V02_BASE_IMAGE = V02_LANE_SPEC.baseImage;

export const GIT_MIRROR_NAMESPACE = "devops-infra";

export const GIT_MIRROR_MANIFEST_FIELD_MANAGER = "unidesk-hwlab-git-mirror";

export const GIT_MIRROR_SYNC_JOB_PREFIX = "git-mirror-hwlab-sync-manual";

export const GIT_MIRROR_LEGACY_CRONJOB = "git-mirror-hwlab-sync";

export const G14_OBSERVABILITY_NAMESPACE = "devops-infra";

export const G14_OBSERVABILITY_FIELD_MANAGER = "unidesk-g14-observability";

export const G14_PROMETHEUS_OPERATOR_VERSION = "v0.91.0";

export const G14_PROMETHEUS_VERSION = "v3.12.0";

export const G14_PROMETHEUS_NAME = "g14-shared";

export const G14_PROMETHEUS_SERVICE = "prometheus-g14-shared";

export const G14_PROMETHEUS_SERVICE_ACCOUNT = "g14-observability-prometheus";

export const G14_PROMETHEUS_OPERATOR_RELEASE_ASSET = `https://github.com/prometheus-operator/prometheus-operator/releases/download/${G14_PROMETHEUS_OPERATOR_VERSION}/bundle.yaml`;

export const V02_SERVICE_IDS = [...V02_LANE_SPEC.serviceIds];

export const V02_CLOUD_WEB_URL = V02_LANE_SPEC.publicWebUrl;

export const V02_CLOUD_API_URL = V02_LANE_SPEC.publicApiUrl;

export const V02_OBSERVABILITY_SERVICE_IDS = [
  "hwlab-agent-skills",
  "hwlab-cloud-api",
  "hwlab-cloud-web",
  "hwlab-deepseek-proxy",
  "hwlab-edge-proxy",
];

export const V02_OBSERVABILITY_EXPECTED_TARGET_COUNT = V02_OBSERVABILITY_SERVICE_IDS.length;

export const V02_OBSERVABILITY_QUERIES = {
  scrapeReachable: 'up{namespace="hwlab-v02"}',
  sidecarServing: 'hwlab_service_up{namespace="hwlab-v02"}',
  businessHealthProbe: 'hwlab_service_health_probe_success{namespace="hwlab-v02"}',
  healthProbeConfigured: 'hwlab_service_health_probe_configured{namespace="hwlab-v02"}',
  healthProbeStatusCode: 'hwlab_service_health_probe_status_code{namespace="hwlab-v02"}',
  healthProbeDurationSeconds: 'hwlab_service_health_probe_duration_seconds{namespace="hwlab-v02"}',
  processUptimeSeconds: 'hwlab_service_process_uptime_seconds{namespace="hwlab-v02"}',
  scrapeDurationSeconds: 'scrape_duration_seconds{namespace="hwlab-v02"}',
  scrapeSamplesScraped: 'scrape_samples_scraped{namespace="hwlab-v02"}',
};

export const V02_OBSERVABILITY_CLOSEOUT_QUERY_NAMES = ["scrapeReachable", "sidecarServing", "businessHealthProbe"] as const;

export const V02_OBSERVABILITY_BOOLEAN_QUERY_NAMES = [...V02_OBSERVABILITY_CLOSEOUT_QUERY_NAMES, "healthProbeConfigured"];

export function v02PipelineServiceIds(): string[] {
  return [...V02_SERVICE_IDS];
}

export const G14_CI_TOOLS_IMAGE_REPO = "127.0.0.1:5000/hwlab/hwlab-ci-node-tools";

export const G14_CI_TOOLS_BASE_TAG = "node22-alpine-v1";

export const DEFAULT_INTERVAL_SECONDS = 600;

export const DEFAULT_MAX_CYCLES = 0;

export const DEFAULT_TIMEOUT_SECONDS = 1800;

export const G14_BRIEF_INDEX_ISSUE = 7;

export const BEIJING_OFFSET_MS = 8 * 60 * 60 * 1000;

export const V02_BUILD_TASKRUN_WARNING_SECONDS = 120;

export const V02_BUILD_TASKRUN_CRITICAL_SECONDS = 180;

export const V02_CONTROL_PLANE_REFRESH_TTL_MS = 5 * 60 * 1000;

export const V02_CONTROL_PLANE_REFRESH_LOCK_STALE_MS = 5 * 60 * 1000;

export const V02_GIT_MIRROR_PRESYNC_MAX_WAIT_MS = 120 * 1000;

export const V02_GIT_MIRROR_PRESYNC_LOCK_STALE_MS = 5 * 60 * 1000;

export const V02_GIT_MIRROR_PRESYNC_POLL_MS = 3 * 1000;

export type G14MonitorLane = "g14" | HwlabRuntimeLane;

export interface G14MonitorOptions {
  lane: G14MonitorLane;
  intervalSeconds: number;
  maxCycles: number;
  once: boolean;
  dryRun: boolean;
  worker: boolean;
  timeoutSeconds: number;
}

export interface G14RecordRolloutOptions {
  prNumber: number;
  sourceCommit?: string;
  pipelineRun?: string;
  gitopsRevision?: string;
  mergedAt?: string;
  pipelineSucceededAt?: string;
  finishedAt?: string;
  dryRun: boolean;
}

export interface G14ControlPlaneOptions {
  action: "status" | "closeout" | "apply" | "trigger-current" | "refresh" | "cleanup-runs" | "cleanup-released-pvs" | "runtime-migration";
  lane: HwlabRuntimeLane | "g14" | "all";
  dryRun: boolean;
  confirm: boolean;
  wait: boolean;
  rerun: boolean;
  allowLiveDbRead: boolean;
  timeoutSeconds: number;
  minAgeMinutes: number;
  limit: number;
  sourceCommit?: string;
  pipelineRun?: string;
  history: boolean;
}

export interface G14LegacyRetirementOptions {
  action: "status" | "plan" | "execute";
  dryRun: boolean;
  confirm: boolean;
  wait: boolean;
  timeoutSeconds: number;
  reason: string;
}

export type V02StatusTargetMode = "latest-source-head" | "source-commit" | "pipeline-run";

export interface V02ControlPlaneStatusTarget {
  sourceCommit?: string | null;
  pipelineRun?: string | null;
  mode?: V02StatusTargetMode;
  includeHistory?: boolean;
}

export interface G14ToolsImageOptions {
  action: "status" | "build";
  name: "ci-node-tools";
  tag: string;
  dockerfile: string;
  dryRun: boolean;
  confirm: boolean;
  timeoutSeconds: number;
}

export interface G14UpstreamImageOptions {
  action: "status" | "ensure";
  name: "openfga";
  tag: string;
  dryRun: boolean;
  confirm: boolean;
  timeoutSeconds: number;
}

export interface G14GitMirrorOptions {
  action: "status" | "apply" | "sync" | "flush";
  lane: HwlabRuntimeLane;
  dryRun: boolean;
  confirm: boolean;
  wait: boolean;
  timeoutSeconds: number;
}

export interface G14ObservabilityOptions {
  action: "status" | "apply" | "query" | "targets" | "boundary" | "closeout";
  lane: "v02";
  dryRun: boolean;
  confirm: boolean;
  wait: boolean;
  timeoutSeconds: number;
  query: string;
  expectCount?: number;
  expectValue?: string;
}

export interface G14SecretOptions {
  action: "status" | "ensure" | "delete";
  lane: HwlabRuntimeLane;
  dryRun: boolean;
  confirm: boolean;
  name: string;
  key?: string;
  preset: "openfga" | "master-server-admin-api-key" | "generic-delete";
  timeoutSeconds: number;
}

export interface CommandJsonResult {
  ok: boolean;
  command: string[];
  exitCode: number | null;
  stdout: string;
  stderr: string;
  parsed: unknown | null;
  durationMs?: number;
  timedOut?: boolean;
  stdoutBytes?: number;
  stderrBytes?: number;
}

export interface RemoteAsyncCommandSpec {
  script: string;
  timeoutSeconds: number;
  label: string;
  token: string;
  command: string[];
}

export interface ShellSection {
  stdout: string;
  exitCode: number | null;
}

export interface OpenPullRequest {
  number: number;
  title?: string;
  url?: string;
  baseRefName?: string;
  headRefName?: string;
  mergeable?: string | null;
  mergeStateStatus?: string | null;
  draft?: boolean;
}

export interface CiServiceMetric {
  taskRun: string;
  serviceId: string;
  status: string;
  durationSeconds: number | null;
  buildBackend: string | null;
  reusedFrom: string | null;
  imageTag: string | null;
  sourceCommitId: string | null;
}

export interface CiPipelineMetrics {
  ok: boolean;
  pipelineRun: string;
  serviceTotal: number;
  reusedCount: number;
  rebuildCount: number;
  reusedServices: string[];
  rebuildServices: string[];
  services: CiServiceMetric[];
  degradedReason?: string;
  rawText?: string;
}

export interface V02PrCommentInput {
  pr: OpenPullRequest;
  phase: string;
  state: "waiting-ci" | "blocked" | "merge-failed" | "cd-started" | "cd-succeeded" | "cd-superseded" | "cd-failed" | "cd-timeout" | "cd-blocked";
  startedAt: string;
  observedAt: string;
  elapsedSeconds: number | null;
  preflight?: Record<string, unknown>;
  merge?: Record<string, unknown>;
  sourceCommit?: string | null;
  pipelineRun?: string | null;
  cd?: Record<string, unknown>;
  flush?: Record<string, unknown>;
  dryRun?: boolean;
  message?: string;
}
