export const HWLAB_NODE_CONTROL_PLANE_CONFIG_PATH = "config/hwlab-node-control-plane.yaml";

export type InfraAction = "plan" | "status" | "apply";
export type ToolsImageAction = "status" | "build" | "logs";
export type TektonInstallAction = "status" | "apply" | "logs";
export type ArgoAction = "status" | "apply" | "logs";
export type EgressBenchmarkAction = "benchmark" | "status" | "logs";
export type CiBuildBenchmarkAction = "benchmark" | "status" | "logs";
export type K3sInstallAction = "plan" | "install" | "status";

export interface InfraOptions {
  action: InfraAction;
  node: string;
  lane: string;
  dryRun: boolean;
  confirm: boolean;
  timeoutSeconds: number;
}

export interface ToolsImageOptions {
  action: ToolsImageAction;
  node: string;
  lane: string;
  dryRun: boolean;
  confirm: boolean;
  timeoutSeconds: number;
  tailLines: number;
}

export interface TektonInstallOptions {
  action: TektonInstallAction;
  node: string;
  lane: string;
  dryRun: boolean;
  confirm: boolean;
  timeoutSeconds: number;
  tailLines: number;
}

export interface ArgoOptions {
  action: ArgoAction;
  node: string;
  lane: string;
  dryRun: boolean;
  confirm: boolean;
  timeoutSeconds: number;
  tailLines: number;
}

export interface EgressBenchmarkOptions {
  action: EgressBenchmarkAction;
  node: string;
  lane: string;
  profile: "no-mirror";
  dryRun: boolean;
  confirm: boolean;
  samples: number;
  sampleTimeoutSeconds: number;
  timeoutSeconds: number;
  tailLines: number;
}

export interface CiBuildBenchmarkOptions {
  action: CiBuildBenchmarkAction;
  node: string;
  lane: string;
  profile: string;
  dryRun: boolean;
  confirm: boolean;
  timeoutSeconds: number;
  tailLines: number;
}

export interface K3sInstallOptions {
  action: K3sInstallAction;
  node: string;
  lane: string;
  dryRun: boolean;
  confirm: boolean;
  timeoutSeconds: number;
  tailLines: number;
}

export interface CiBuildBenchmarkCachePolicy {
  noPipelineRunReuse: boolean;
  forceFullBuild: boolean;
  forbidGitopsCatalogReuse: boolean;
  forbidDependencyCache: boolean;
  forbidBuildkitCache: boolean;
  forbidRegistryMirror: boolean;
  forbidLocalPreheatedImages: boolean;
}

export interface CiBuildBenchmarkProfileSpec {
  profile: string;
  runtimeLaneConfigRef: string;
  pipelineRunPrefix: string;
  catalogPathTemplate: string;
  imageTagMode: "full";
  pipelineTimeoutSeconds: number;
  cachePolicy: CiBuildBenchmarkCachePolicy;
  requiredTimings: readonly string[];
  failureFamilies: readonly string[];
}

export type ControlPlaneEgressProxySpec = ControlPlaneK8sServiceEgressProxySpec | ControlPlaneHostRouteEgressProxySpec;

export interface ControlPlaneK8sServiceEgressProxySpec {
  mode: "k8s-service-cluster-ip";
  clientName: string;
  namespace: string;
  serviceName: string;
  port: number;
  sourceConfigRef: string | null;
  sourceFingerprint: string | null;
  sourceRef: string;
  sourceKey: string;
  sourceType: "subscription-url" | "master-shadowsocks";
  preferredOutbound: "vless-reality" | "hysteria2" | null;
  noProxy: readonly string[];
}

export interface ControlPlaneHostRouteEgressProxySpec {
  mode: "host-route";
  clientName: string;
  hostProxyConfigRef: string;
  proxyEnvPath: string;
  proxyUrl: string;
  noProxy: readonly string[];
}

export interface ControlPlaneGitMirrorEgressProxySpec {
  mode: "node-global" | "host-route" | "direct";
  required: boolean;
  podHostNetwork: boolean;
  injectPodEnv: boolean;
}

export interface ControlPlaneRuntimeProxySpec {
  enabled: boolean;
  mode: "host-route";
  configRef: string | null;
  hostNetwork: boolean;
  injectEnv: boolean;
  deployments: readonly string[];
  statefulSets: readonly string[];
}

export type ControlPlaneGitMirrorGithubTransportSpec =
  | {
    mode: "ssh";
    privateKeySecretKey: string;
    privateKeySourceRef: string;
    privateKeySourceKey: string;
    privateKeySourceEncoding: "plain" | "base64";
    knownHostsSecretKey: string | null;
    knownHostsSourceRef: string | null;
    knownHostsSourceKey: string | null;
    knownHostsSourceEncoding: "plain" | "base64" | null;
  }
  | {
    mode: "https";
    username: string;
    tokenSecretName: string;
    tokenSecretKey: string;
    tokenSourceRef: string;
    tokenSourceKey: string;
  };

export interface ControlPlaneTektonGitWorkspaceSecretSpec {
  name: string;
  namespace: string;
  sourceRefFrom: "gitMirror.githubTransport";
  privateKeySecretKey: string;
  knownHostsSecretKey: string;
}

export interface ControlPlaneTektonRuntimeObserverRbacSpec {
  namespace: string;
  roleName: string;
  roleBindingName: string;
}

export interface ControlPlaneTektonArgoObserverRbacSpec {
  namespace: string;
  roleName: string;
  roleBindingName: string;
}

export interface ControlPlaneTektonInstallManifestSpec {
  name: string;
  url: string;
}

export interface ControlPlaneTektonInstallSpec {
  enabled: boolean;
  sourceKind: "url";
  version: string;
  fieldManager: string;
  manifests: readonly ControlPlaneTektonInstallManifestSpec[];
  requiredCrds: readonly string[];
  expectedDeploymentNamespaces: readonly string[];
  readinessTimeoutSeconds: number;
  runtimeProxy: ControlPlaneRuntimeProxySpec;
}

export interface ControlPlaneNodeSpec {
  id: string;
  route: string;
  kubeRoute: string;
  k3s: ControlPlaneK3sNodeSpec | null;
  registry: ControlPlaneRegistrySpec;
  egressProxy: ControlPlaneEgressProxySpec | null;
}

export type ControlPlaneRegistrySpec = ControlPlaneHostDockerRegistrySpec | ControlPlaneK8sWorkloadRegistrySpec;

export interface ControlPlaneHostDockerRegistrySpec {
  mode: "host-docker";
  endpoint: string;
}

export interface ControlPlaneK8sWorkloadRegistrySpec {
  mode: "k8s-workload";
  endpoint: string;
  namespace: string;
  deploymentName: string;
  serviceName: string;
  pvcName: string;
  storage: string;
  image: string;
  imagePullPolicy: "Always" | "IfNotPresent" | "Never";
  containerPort: number;
  listenHost: string;
  listenPort: number;
  hostNetwork: boolean;
  deleteEnabled: boolean;
}

export interface ControlPlaneK3sNodeSpec {
  serviceName: string;
  dropInPath: string;
  nodeStatusName: string;
  clusterConfigRef: string | null;
  execStartPre: readonly (readonly string[])[];
  install: ControlPlaneK3sInstallSpec | null;
  serverArgs: readonly string[];
  kubelet: { maxPods: number };
}

export interface ControlPlaneK3sInstallSpec {
  enabled: boolean;
  channel: string;
  version: string;
  installScriptUrl: string;
  binaryUrl: string;
  sha256Url: string;
  expectedSha256: string;
  hostProxyConfigRef: string;
  proxyEnvPath: string;
  registriesYamlPath: string;
  localRegistry: {
    containerName: string;
    image: string;
    canonicalImage: string;
    bind: string;
  };
  state: {
    dir: string;
    logPath: string;
    statusPath: string;
  };
  downloads: {
    connectTimeoutSeconds: number;
    maxTimeSeconds: number;
    retry: number;
    retryDelaySeconds: number;
  };
}

export interface DockerfileInlineSpec {
  filename: string;
  lines: readonly string[];
}

export interface ImageRewriteSpec {
  source: string;
  pullImage: string;
  target: string;
}

export interface ControlPlaneTargetSpec {
  id: string;
  node: string;
  lane: string;
  enabled: boolean;
  ciNamespace: string;
  runtimeNamespace: string;
  source: {
    repository: string;
    branch: string;
    sourceAuthority: {
      mode: "gitMirrorSnapshot" | "giteaSnapshot";
      resolver: "k8s-git-mirror" | "gitea-mirror";
      giteaMirrorRepoKey?: string;
      allowHostGit: false;
      allowHostWorkspace: false;
      allowGithubDirectInPipeline: false;
    };
    sourceSnapshot: {
      stageRefPrefix: string;
      missingObjectPolicy: "fail-fast";
      refreshPolicy: "sync-before-snapshot" | "gitea-controlled-snapshot";
    };
  };
  gitops: { branch: string; path: string };
  gitMirror: {
    namespace: string;
    serviceReadName: string;
    serviceWriteName: string;
    cachePvcName: string;
    cachePvcStorage: string;
    cacheHostPath: string | null;
    servicePort: number;
    readContainerPort: number;
    writeContainerPort: number;
    deploymentReplicas: number;
    secretName: string;
    syncConfigMapName: string;
    syncJobPrefix: string;
    flushJobPrefix: string;
    readUrl: string;
    writeUrl: string;
    egressProxy: ControlPlaneGitMirrorEgressProxySpec | null;
    githubTransport: ControlPlaneGitMirrorGithubTransportSpec;
  };
  tekton: {
    install: ControlPlaneTektonInstallSpec;
    pipelineName: string;
    serviceAccountName: string;
    pipelineRunPrefix: string;
    gitWorkspaceSecret: ControlPlaneTektonGitWorkspaceSecretSpec;
    runtimeObserverRbac: ControlPlaneTektonRuntimeObserverRbacSpec;
    argoObserverRbac: ControlPlaneTektonArgoObserverRbacSpec;
      toolsImage: {
        output: string;
        imagePullPolicy: "Always" | "IfNotPresent" | "Never";
        sourceKind: "dockerfile" | "docker-compose";
        context: string;
      dockerfile?: string;
      dockerfileInline?: DockerfileInlineSpec;
      composeFile?: string;
      buildArgs: Readonly<Record<string, string>>;
      buildNetwork: string | null;
      publicBaseImages: readonly string[];
      buildOwner: string;
      buildMode: string;
    };
  };
  ciBuildBenchmarks: readonly CiBuildBenchmarkProfileSpec[];
  argo: {
    namespace: string;
    projectName: string;
    applicationName: string;
    applicationFile: string;
    install: {
      enabled: boolean;
      sourceKind: "url";
      version: string;
      manifestUrl: string;
      fieldManager: string;
      imagePullPolicy: "Always" | "IfNotPresent" | "Never";
      preloadImages: readonly string[];
      imageRewrites: readonly ImageRewriteSpec[];
      requiredCrds: readonly string[];
      expectedDeployments: readonly string[];
      expectedStatefulSets: readonly string[];
      readinessTimeoutSeconds: number;
      runtimeProxy: ControlPlaneRuntimeProxySpec;
    };
  };
}

export interface ControlPlaneImagePolicy {
  requireReproducibleBuildSource: boolean;
  forbidPrivateOrNodeLocalImagesAsInputs: boolean;
  allowNodeLocalRegistryAsBuildOutput: boolean;
  requiredSourceKinds: readonly ("dockerfile" | "docker-compose")[];
}

export interface ControlPlaneConfig {
  version: number;
  kind: string;
  metadata: { owner: string; relatedIssues: readonly number[] };
  imagePolicy: ControlPlaneImagePolicy;
  nodes: Record<string, ControlPlaneNodeSpec>;
  targets: readonly ControlPlaneTargetSpec[];
}

export interface HwlabNodeControlPlaneSourceWorkspaceBootstrapSpec {
  readonly configPath: string;
  readonly targetId: string;
  readonly node: string;
  readonly lane: string;
  readonly ciNamespace: string;
  readonly serviceAccountName: string;
  readonly toolsImage: string;
  readonly imagePullPolicy: "Always" | "IfNotPresent" | "Never";
  readonly gitReadUrl: string;
  readonly gitWriteUrl: string;
  readonly gitMirrorNamespace: string;
}
