/**
 * Copyright (c) OpenLens Maintainers. All rights reserved.
 * Licensed under MIT License. See LICENSE in root directory for more information.
 */
import type { KubeObjectConstructor, KubeJsonApiDataFor, KubeObjectMetadata, KubeJsonApiData, KubeObject, KubeObjectScope, Scale } from "@openlens/kube-object";
import { KubeStatus } from "@openlens/kube-object";
import type { IKubeWatchEvent } from "./kube-watch-event";
import type { KubeJsonApi } from "./kube-json-api";
import type { Disposer } from "@openlens/utilities";
import type { RequestInit, Response } from "@openlens/node-fetch";
import type { Patch } from "rfc6902";
import type { PartialDeep } from "type-fest";
import type { Logger } from "@openlens/logger";
import type { ScaleCreateOptions } from "@openlens/kube-object/src/types/scale";
/**
 * The options used for creating a `KubeApi`
 */
export interface KubeApiOptions<T extends KubeObject, Data extends KubeJsonApiDataFor<T> = KubeJsonApiDataFor<T>> extends DerivedKubeApiOptions {
    /**
     * base api-path for listing all resources, e.g. "/api/v1/pods"
     *
     * Must be provided either here or under `objectConstructor.apiBase`
     * @deprecated should be specified by `objectConstructor`
     */
    apiBase?: string;
    /**
     * The constructor for the kube objects returned from the API
     */
    objectConstructor: KubeObjectConstructor<T, Data>;
    /**
     * Must be provided either here or under `objectConstructor.namespaced`
     * @deprecated should be specified by `objectConstructor`
     */
    isNamespaced?: boolean;
    /**
     * Must be provided either here or under `objectConstructor.kind`
     * @deprecated should be specified by `objectConstructor`
     */
    kind?: string;
}
export interface DerivedKubeApiOptions {
    /**
     * If the API uses a different API endpoint (e.g. apiBase) depending on the cluster version,
     * fallback API bases can be listed individually.
     *
     * The first (existing) API base is used in the requests, if apiBase is not found.
     *
     * This option only has effect if {@link DerivedKubeApiOptions.checkPreferredVersion} is `true`.
     */
    fallbackApiBases?: string[];
    /**
     * This option is useful for protecting against newer versions on the same apiBase from being
     * used. So that if a certain type only supports `v1`, or `v2` of some kind and then the `v3`
     * version becomes the `preferredVersion` on the server but still has `v2` then the `v2` version
     * will be used instead.
     *
     * This can help to prevent crashes in the future if the shape of a kind sufficently changes.
     *
     * The order is important. It should be sorted and the first entry should be the most preferable.
     *
     * This option only has effect if {@link DerivedKubeApiOptions.checkPreferredVersion} is `true`
     */
    allowedUsableVersions?: Partial<Record<string, [string, ...string[]]>>;
    /**
     * If `true` then will check all declared apiBases against the kube api server
     * for the first accepted one.
     *
     * @default false
     */
    checkPreferredVersion?: boolean;
    /**
     * The api instance to use for making requests
     *
     * @default apiKube
     */
    request?: KubeJsonApi;
}
export interface KubeApiQueryParams {
    watch?: boolean | number;
    resourceVersion?: string;
    timeoutSeconds?: number;
    limit?: number;
    continue?: string;
    labelSelector?: string | string[];
    fieldSelector?: string | string[];
}
export interface KubeApiListOptions {
    namespace?: string;
    reqInit?: RequestInit;
}
export interface IKubePreferredVersion {
    preferredVersion?: {
        version: string;
    };
}
export interface KubeApiResource {
    categories?: string[];
    group?: string;
    kind: string;
    name: string;
    namespaced: boolean;
    shortNames?: string[];
    singularName: string;
    storageVersionHash?: string;
    verbs: string[];
    version?: string;
}
export interface KubeApiResourceList {
    apiVersion?: string;
    groupVersion?: string;
    kind?: string;
    resources: KubeApiResource[];
}
export interface KubeApiResourceVersion {
    groupVersion: string;
    version: string;
}
export interface KubeApiResourceVersionList {
    apiVersion: string;
    kind: string;
    name: string;
    preferredVersion: KubeApiResourceVersion;
    versions: KubeApiResourceVersion[];
}
export type PropagationPolicy = undefined | "Orphan" | "Foreground" | "Background";
export type KubeApiWatchCallback<T extends KubeJsonApiData = KubeJsonApiData> = (data: IKubeWatchEvent<T> | null, error: KubeStatus | Response | null | Record<string, unknown>) => void;
export interface KubeApiWatchOptions<Object extends KubeObject, Data extends KubeJsonApiDataFor<Object>> {
    /**
     * If the resource is namespaced then the default is `"default"`
     */
    namespace?: string;
    /**
     * This will be called when either an error occurs or some data is received
     */
    callback?: KubeApiWatchCallback<Data>;
    /**
     * This is a way of aborting the request
     */
    abortController?: AbortController;
    /**
     * The ID used for tracking within logs
     */
    watchId?: string;
    /**
     * @default false
     */
    retry?: boolean;
    /**
     * timeout in seconds
     */
    timeout?: number;
}
export type KubeApiPatchType = "merge" | "json" | "strategic";
export declare const patchTypeHeaders: Record<KubeApiPatchType, string>;
export interface ResourceDescriptor {
    /**
     * The name of the kubernetes resource
     */
    name: string;
    /**
     * The namespace that the resource lives in (if the resource is namespaced)
     *
     * Note: if not provided and the resource kind is namespaced, then this defaults to `"default"`
     */
    namespace?: string;
}
export interface SubResourceDescriptor {
    subResource: string;
}
export type SpecificResourceDescriptor<Scope extends KubeObjectScope> = {
    /**
     * The name of the kubernetes resource
     */
    name: string;
} & (Scope extends KubeObjectScope.Cluster ? {} : Scope extends KubeObjectScope.Namespace ? {
    /**
     * The namespace that the resource lives in
     */
    namespace: string;
} : {
    namespace?: string;
});
export type NamespacedResourceDescriptor = SpecificResourceDescriptor<KubeObjectScope.Namespace>;
export type ClusterScopedResourceDescriptor = SpecificResourceDescriptor<KubeObjectScope.Cluster>;
export interface DeleteResourceDescriptor extends ResourceDescriptor {
    /**
     * This determinines how child resources should be handled by kubernetes
     *
     * @default "Background"
     */
    propagationPolicy?: PropagationPolicy;
}
export interface KubeApiDependencies {
    readonly logger: Logger;
    readonly maybeKubeApi: KubeJsonApi | undefined;
}
export declare class KubeApi<Object extends KubeObject = KubeObject, Data extends KubeJsonApiDataFor<Object> = KubeJsonApiDataFor<Object>> {
    protected readonly dependencies: KubeApiDependencies;
    readonly kind: string;
    readonly apiVersion: string;
    apiBase: string;
    apiPrefix: string;
    apiGroup: string;
    apiVersionPreferred: string | undefined;
    readonly apiResource: string;
    readonly isNamespaced: boolean;
    readonly objectConstructor: KubeObjectConstructor<Object, Data>;
    protected readonly request: KubeJsonApi;
    protected readonly resourceVersions: Map<string, string>;
    protected readonly watchDisposer: Disposer | undefined;
    private watchId;
    protected readonly doCheckPreferredVersion: boolean;
    protected readonly fullApiPathname: string;
    protected readonly fallbackApiBases: string[] | undefined;
    protected readonly allowedUsableVersions: Partial<Record<string, string[]>> | undefined;
    constructor(dependencies: KubeApiDependencies, opts: KubeApiOptions<Object, Data>);
    get apiVersionWithGroup(): string;
    /**
     * Returns the latest API prefix/group that contains the required resource.
     * First tries fullApiPathname, then urls in order from fallbackApiBases.
     */
    private getLatestApiPrefixGroup;
    protected checkPreferredVersion(): Promise<void>;
    setResourceVersion(namespace: string | undefined, newVersion: string): void;
    getResourceVersion(namespace?: string): string | undefined;
    refreshResourceVersion(params?: KubeApiListOptions): Promise<Object[] | null>;
    private computeApiBase;
    /**
     * This method differs from {@link formatUrlForNotListing} because this treats `""` as "all namespaces"
     * NOTE: This is also useful for watching
     * @param namespace The namespace to list in or `""` for all namespaces
     */
    formatUrlForListing(namespace: string | undefined, query?: Partial<KubeApiQueryParams>): string;
    /**
     * Format a URL pathname and query for acting upon a specific resource.
     */
    formatUrlForNotListing({ name, namespace }?: Partial<ResourceDescriptor>): string;
    /**
     * @deprecated use {@link formatUrlForNotListing} or {@link formatUrlForListing} instead
     */
    getUrl(resource?: Partial<ResourceDescriptor>, query?: Partial<KubeApiQueryParams>): string;
    protected normalizeQuery(query?: Partial<KubeApiQueryParams>): Partial<KubeApiQueryParams>;
    protected parseResponse(data: unknown, namespace?: string): Object | Object[] | null;
    private ensureMetadataSelfLink;
    list({ namespace, reqInit }?: KubeApiListOptions, query?: KubeApiQueryParams): Promise<Object[] | null>;
    get(desc: ResourceDescriptor, query?: KubeApiQueryParams): Promise<Object | null>;
    create({ name, namespace }: Partial<ResourceDescriptor>, partialData?: PartialDeep<Object>): Promise<Object | null>;
    update({ name, namespace }: ResourceDescriptor, data: PartialDeep<Object>): Promise<Object | null>;
    /**
     * An internal method for requesting the `/scale` sub-resource if it exists
     */
    protected getResourceScale(desc: ResourceDescriptor): Promise<Scale>;
    /**
     * An internal method for requesting the `/scale` sub-resource if it exists
     */
    protected scaleResource(desc: ResourceDescriptor, data: ScaleCreateOptions): Promise<Scale>;
    patch(desc: ResourceDescriptor, data: PartialDeep<Object>): Promise<Object | null>;
    patch(desc: ResourceDescriptor, data: PartialDeep<Object>, strategy: "strategic" | "merge"): Promise<Object | null>;
    patch(desc: ResourceDescriptor, data: Patch, strategy: "json"): Promise<Object | null>;
    patch(desc: ResourceDescriptor, data: PartialDeep<Object> | Patch, strategy: KubeApiPatchType): Promise<Object | null>;
    /**
     * Some k8s resources might implement special "delete" (e.g. pod.api)
     * See also: https://kubernetes.io/docs/concepts/scheduling-eviction/api-eviction/
     * By default should work same as delete()
     */
    evict(desc: DeleteResourceDescriptor): Promise<KubeStatus | KubeObject | unknown>;
    delete({ propagationPolicy, ...desc }: DeleteResourceDescriptor): Promise<KubeJsonApiData<import("@openlens/kube-object").KubeJsonApiObjectMetadata<KubeObjectScope>, unknown, unknown>>;
    getWatchUrl(namespace?: string, query?: KubeApiQueryParams): string;
    watch(opts?: KubeApiWatchOptions<Object, Data>): Disposer;
    protected modifyWatchEvent(event: IKubeWatchEvent<KubeJsonApiData<KubeObjectMetadata>>): void;
}
