import * as k8s from '@kubernetes/client-node';
export interface ContainerResources {
    cpu: string | null;
    memory: string | null;
}
export interface ContainerDetail {
    name: string;
    image: string;
    requests: ContainerResources;
    limits: ContainerResources;
}
export interface ReplicaInfo {
    desired?: number;
    ready?: number;
    available?: number;
    unavailable?: number;
    updated?: number;
}
export interface ResourceDetail {
    replicas: ReplicaInfo;
    containers: ContainerDetail[];
}
export interface ContainerMetrics {
    name: string;
    usage: {
        cpu: string;
        memory: string;
    };
}
export interface PodMetrics {
    name: string;
    containers: ContainerMetrics[];
}
export declare class KubernetesService {
    private readonly logger;
    /**
     * Public wrapper to expose a patched KubeConfig instance.
     * Use this when you need to instantiate k8s client classes directly
     * (e.g. k8s.Log for log streaming) rather than through getKubeClient().
     */
    makeKubeConfig(kubeconfigContent: string): k8s.KubeConfig;
    /**
     * Patch the kubeconfig server URL using KUBECONFIG_SERVER_OVERRIDE env var,
     * then load it into a KubeConfig instance.
     * All public methods that accept a kubeconfig string go through this helper
     * so the patch is applied exactly once regardless of which service calls us.
     */
    private loadKubeconfig;
    /**
     * Get Kubernetes client from kubeconfig string
     */
    getKubeClient(kubeconfigContent: string): {
        coreApi: k8s.CoreV1Api;
        appsApi: k8s.AppsV1Api;
        batchApi: k8s.BatchV1Api;
        networkingApi: k8s.NetworkingV1Api;
    };
    /**
     * Canonicalize a parsed spec into the exact JSON string that will be stored
     * on K8s under `metadata.annotations["kubectl.kubernetes.io/last-applied-configuration"]`.
     *
     * MUTATES `spec`: ensures `metadata.annotations` exists (possibly as {}) and
     * strips any pre-existing last-applied-configuration key before serializing.
     * The returned string is the canonical form that drift detection will hash —
     * both sides (apply-time and reconcile-time) must produce identical bytes.
     *
     * Keep this the single source of truth — do not inline this logic elsewhere.
     */
    buildLastAppliedConfiguration(spec: any): string;
    /**
     * Apply manifest from YAML string
     * Supports multiple documents separated by ---
     */
    applyManifest(kubeconfigContent: string, manifestYaml: string): Promise<any[]>;
    /**
     * Replace a manifest using HTTP PUT (full replace — removes keys not in payload).
     * Creates the resource if it doesn't exist yet.
     */
    replaceManifest(kubeconfigContent: string, manifestYaml: string): Promise<any[]>;
    /**
     * Delete a Kubernetes resource
     */
    deleteResource(kubeconfigContent: string, kind: string, name: string, namespace?: string): Promise<void>;
    /**
     * Get a Kubernetes resource
     */
    getResource(kubeconfigContent: string, kind: string, name: string, namespace?: string): Promise<any>;
    /**
     * Wait for a resource to be ready
     */
    waitForReady(kubeconfigContent: string, kind: string, name: string, namespace?: string, timeoutMs?: number): Promise<boolean>;
    /**
     * Get pod logs
     */
    getPodLogs(kubeconfigContent: string, podName: string, namespace?: string, containerName?: string, tailLines?: number): Promise<string>;
    /**
     * List resources by kind and namespace
     */
    listResources(kubeconfigContent: string, kind: string, namespace?: string, labelSelector?: string): Promise<any[]>;
    /**
     * List CRD resources (cert-manager Challenges, Orders, etc.) via KubernetesObjectApi.
     */
    listCrdResources(kubeconfigContent: string, kind: string, namespace?: string): Promise<any[]>;
    listResourcesByLabel(kubeconfigContent: string, kind: string, namespace: string, labelSelector: string): Promise<any[]>;
    /**
     * Get resource details including container specs (requests/limits) and replica info.
     * Returns structured data for Deployment, StatefulSet, DaemonSet.
     */
    getResourceDetail(kubeconfigContent: string, kind: string, name: string, namespace?: string): Promise<ResourceDetail | null>;
    /**
     * Get pod-level CPU/memory usage from the Metrics API (metrics.k8s.io).
     * Requires metrics-server to be installed on the cluster.
     */
    getPodMetrics(kubeconfigContent: string, namespace?: string, labelSelector?: string): Promise<PodMetrics[]>;
    /**
     * Read a single pod as V1Pod. Returns null if not found.
     */
    readPod(kubeconfigContent: string, namespace: string, podName: string): Promise<k8s.V1Pod | null>;
    /**
     * List pods matching a label selector.
     */
    listPodsByLabel(kubeconfigContent: string, namespace: string, labelSelector: string): Promise<k8s.V1Pod[]>;
    /**
     * List events that reference the given pod (involvedObject.name filter).
     */
    listPodEvents(kubeconfigContent: string, namespace: string, podName: string): Promise<k8s.CoreV1Event[]>;
    /**
     * Check whether a Secret exists in the namespace.
     */
    checkSecretExists(kubeconfigContent: string, namespace: string, name: string): Promise<boolean>;
    /**
     * Check whether a ConfigMap exists in the namespace.
     */
    checkConfigMapExists(kubeconfigContent: string, namespace: string, name: string): Promise<boolean>;
    /**
     * Watch pod events in a namespace filtered by label selector. Uses the
     * Kubernetes Watch API — events are delivered as they happen.
     *
     * Call `abortController.abort()` to stop the watch.
     */
    watchPodEvents(kubeconfigContent: string, namespace: string, labelSelector: string, onEvent: (type: string, pod: k8s.V1Pod) => void | Promise<void>, abortController: AbortController): Promise<void>;
    /**
     * Discover which ConfigMaps and Secrets a workload uses via envFrom and env[].valueFrom.
     * Returns deduplicated lists of names.
     * Falls back to empty lists if the workload does not exist yet.
     */
    getWorkloadEnvSources(kubeconfigContent: string, name: string, namespace?: string, kind?: string): Promise<{
        configMaps: string[];
        secrets: string[];
    }>;
    /**
     * Execute a command in a pod and return stdout.
     * Finds the first running pod matching the label selector.
     */
    execInPod(kubeconfigContent: string, namespace: string, labelSelector: string, containerName: string, command: string[]): Promise<string>;
    /**
     * Patch a Kubernetes Secret with new stringData entries.
     */
    patchSecret(kubeconfigContent: string, namespace: string, name: string, stringData: Record<string, string>): Promise<void>;
    /**
     * Trigger a rolling restart of a Deployment by patching the pod template annotation.
     * Equivalent to `kubectl rollout restart deployment/<name>`.
     */
    /**
     * Trigger a rolling restart of a Deployment by patching the pod template annotation.
     * Equivalent to `kubectl rollout restart deployment/<name>`.
     */
    restartDeployment(kubeconfigContent: string, namespace: string, name: string): Promise<void>;
    /**
     * Equivalent to `kubectl set image deployment/<name> <container>=<image> -n <ns>`.
     * Strategic merge patch only replaces the image of the named container,
     * leaving init containers, sidecars and other spec fields untouched.
     */
    patchDeploymentContainerImage(kubeconfigContent: string, namespace: string, deploymentName: string, containerName: string, newImage: string): Promise<void>;
    /**
     * Read the current image of a container in a Deployment.
     * Returns null if the deployment, container, or image is missing.
     */
    getDeploymentContainerImage(kubeconfigContent: string, namespace: string, deploymentName: string, containerName: string): Promise<string | null>;
    /**
     * Read a file from a PVC by running a temporary busybox pod.
     * The pod is deleted automatically after reading.
     * Use this for distroless containers that don't have shell utilities.
     */
    readPvcFile(kubeconfigContent: string, namespace: string, pvcName: string, filePath: string): Promise<string>;
    /** @deprecated Use getWorkloadEnvSources with kind='Deployment' */
    getDeploymentEnvSources(kubeconfigContent: string, deploymentName: string, namespace?: string): Promise<{
        configMaps: string[];
        secrets: string[];
    }>;
    /**
     * Ensure a Kubernetes namespace exists, creating it if needed.
     * Idempotent — safe to call before every deploy.
     */
    ensureNamespaceExists(kubeconfigContent: string, namespace: string, labels?: Record<string, string>): Promise<void>;
    private getApiVersionForKind;
    private checkResourceReady;
    /**
     * Rewrite the kubeconfig server URL if KUBECONFIG_SERVER_OVERRIDE is set.
     *
     * When the API runs inside the cluster the bootstrap seeder replaces
     * 127.0.0.1 with kubernetes.default.svc so that in-cluster DNS resolves it.
     * In local development that address is unreachable.
     *
     * Set KUBECONFIG_SERVER_OVERRIDE=https://<MASTER_IP>:6443 in .env to have
     * every kubeconfig transparently rewritten before use.
     *
     * Example .env:
     *   KUBECONFIG_SERVER_OVERRIDE=https://1.2.3.4:6443
     */
    patchKubeconfigServer(kubeconfig: string): string;
    /**
     * Normalises the HTTP status code from a @kubernetes/client-node error.
     * v1.x uses `error.code`; older versions used `error.statusCode`.
     */
    private httpCode;
    /**
     * Poll until a Secret exists and is readable in the cluster.
     * Resolves as soon as the Secret is confirmed readable; throws on timeout.
     * Use this to guard operations that depend on a Secret being visible to
     * other controllers (e.g. cert-manager reading hetzner-secret before the
     * ClusterIssuer is applied).
     */
    waitForSecret(kubeconfigContent: string, name: string, namespace: string, timeoutMs?: number): Promise<void>;
    /**
     * Returns true if the Secret exists in the cluster, false if not found.
     */
    secretExists(kubeconfigContent: string, name: string, namespace: string): Promise<boolean>;
    /**
     * Sum allocatable CPU (millicores) and memory (Mi) across all READY nodes.
     * Uses node.status.allocatable which reflects what is schedulable after
     * OS and kubelet reserved resources.
     */
    getNodeAllocatable(kubeconfigContent: string): Promise<{
        cpu: number;
        memory: number;
    }>;
    /**
     * Poll the Kubernetes API until the named node reports Ready=True or the
     * timeout expires. Used after a scale-node action (power_on) to confirm the
     * node rejoined the cluster.
     */
    waitForNodeReady(kubeconfigContent: string, nodeName: string, timeoutMs?: number, intervalMs?: number): Promise<void>;
    /**
     * Mark a node unschedulable. Existing pods continue to run; new ones are
     * not placed on it. Used as a precaution before power-cycling a node during
     * scale-node operations.
     */
    cordonNode(kubeconfigContent: string, nodeName: string): Promise<void>;
    uncordonNode(kubeconfigContent: string, nodeName: string): Promise<void>;
    private setNodeUnschedulable;
    /**
     * Sum resource requests (CPU in millicores, memory in Mi) across all
     * containers in Running pods across all namespaces.
     */
    getPodResourceRequests(kubeconfigContent: string): Promise<{
        cpu: number;
        memory: number;
    }>;
    /**
     * Returns allocatable and currently-requested resources on the master
     * (control-plane) node. Used to gate scheduling of pods that are pinned
     * to the master via `persistenceScope=dedicated`. CPU in millicores, memory in Mi.
     */
    getMasterNodeCapacity(kubeconfigContent: string): Promise<{
        nodeName: string;
        allocatable: {
            cpu: number;
            memory: number;
        };
        requested: {
            cpu: number;
            memory: number;
        };
    } | null>;
    /**
     * Allocatable + currently-requested resources on a specific node by name.
     * Returns null if the node is not found. Used by placement prechecks for
     * `persistenceScope=dedicated` apps that may target the master or a
     * specific worker.
     */
    getNodeCapacityByName(kubeconfigContent: string, nodeName: string): Promise<{
        nodeName: string;
        allocatable: {
            cpu: number;
            memory: number;
        };
        requested: {
            cpu: number;
            memory: number;
        };
    } | null>;
    /**
     * Parse a Kubernetes CPU string to millicores.
     * Examples: "250m" → 250, "2" → 2000, "0.5" → 500
     */
    parseCpu(value: string): number;
    /**
     * Parse a Kubernetes memory string to mebibytes (Mi).
     * Examples: "512Mi" → 512, "1Gi" → 1024, "1073741824" → 1024 (bytes)
     */
    parseMemory(value: string): number;
    private sleep;
}
