// SPDX-License-Identifier: Apache-2.0
import { V1Lease, V1LeaseSpec, V1MicroTime, V1ObjectMeta, } from '@kubernetes/client-node';
import { SoloError } from '../../../../../core/errors/solo-error.js';
import { getReasonPhrase, StatusCodes } from 'http-status-codes';
import { container } from 'tsyringe-neo';
import { sleep } from '../../../../../core/helpers.js';
import { Duration } from '../../../../../core/time/duration.js';
import { InjectTokens } from '../../../../../core/dependency-injection/inject-tokens.js';
import { K8ClientLease } from './k8-client-lease.js';
import { ResourceCreateError, ResourceDeleteError, ResourceReadError, ResourceReplaceError, } from '../../../errors/resource-operation-errors.js';
import { ResourceType } from '../../../resources/resource-type.js';
export class K8ClientLeases {
    coordinationApiClient;
    logger;
    constructor(coordinationApiClient) {
        this.coordinationApiClient = coordinationApiClient;
        this.logger = container.resolve(InjectTokens.SoloLogger);
    }
    async create(namespace, leaseName, holderName, durationSeconds) {
        const lease = new V1Lease();
        const metadata = new V1ObjectMeta();
        metadata.name = leaseName;
        metadata.namespace = namespace.name;
        lease.metadata = metadata;
        const spec = new V1LeaseSpec();
        spec.holderIdentity = holderName;
        spec.leaseDurationSeconds = durationSeconds;
        spec.acquireTime = new V1MicroTime();
        lease.spec = spec;
        let result;
        try {
            result = await this.coordinationApiClient.createNamespacedLease(namespace.name, lease);
        }
        catch (error) {
            throw new ResourceCreateError(ResourceType.LEASE, namespace, leaseName, error);
        }
        this.handleKubernetesClientError(result.response, result.body, 'Failed to create namespaced lease');
        return K8ClientLease.fromV1Lease(result.body);
    }
    async delete(namespace, name) {
        let result;
        try {
            result = await this.coordinationApiClient.deleteNamespacedLease(name, namespace.name);
        }
        catch (error) {
            throw new ResourceDeleteError(ResourceType.LEASE, namespace, name, error);
        }
        this.handleKubernetesClientError(result.response, result.body, 'Failed to delete namespaced lease');
        return result.body;
    }
    async read(namespace, leaseName, timesCalled) {
        let result;
        try {
            result = await this.coordinationApiClient.readNamespacedLease(leaseName, namespace.name);
        }
        catch (error) {
            throw new ResourceReadError(ResourceType.LEASE, namespace, leaseName, error);
        }
        if (result.response?.statusCode === StatusCodes.INTERNAL_SERVER_ERROR && timesCalled < 4) {
            // could be k8s control plane has no resources available
            this.logger.debug(`Retrying readNamespacedLease(${leaseName}, ${namespace}) in 5 seconds because of ${getReasonPhrase(StatusCodes.INTERNAL_SERVER_ERROR)}`);
            await sleep(Duration.ofSeconds(5));
            try {
                return await this.read(namespace, leaseName, timesCalled + 1);
            }
            catch (error) {
                throw new ResourceReadError(ResourceType.LEASE, namespace, leaseName, error);
            }
        }
        this.handleKubernetesClientError(result.response, result.body, 'Failed to read namespaced lease');
        return K8ClientLease.fromV1Lease(result.body);
    }
    async renew(namespace, leaseName, lease) {
        const v1Lease = K8ClientLease.toV1Lease(lease);
        v1Lease.spec.renewTime = new V1MicroTime();
        let result;
        try {
            result = await this.coordinationApiClient.replaceNamespacedLease(leaseName, namespace.name, v1Lease);
        }
        catch (error) {
            throw new ResourceReplaceError(ResourceType.LEASE, namespace, leaseName, error);
        }
        this.handleKubernetesClientError(result.response, result.body, 'Failed to renew namespaced lease');
        return K8ClientLease.fromV1Lease(result.body);
    }
    async transfer(lease, newHolderName) {
        const v1Lease = K8ClientLease.toV1Lease(lease);
        v1Lease.spec.leaseTransitions++;
        v1Lease.spec.renewTime = new V1MicroTime();
        v1Lease.spec.holderIdentity = newHolderName;
        let result;
        try {
            result = await this.coordinationApiClient.replaceNamespacedLease(v1Lease.metadata.name, v1Lease.metadata.namespace, v1Lease);
        }
        catch (error) {
            throw new ResourceReplaceError(ResourceType.LEASE, lease.namespace, v1Lease.metadata.name, error);
        }
        this.handleKubernetesClientError(result.response, result.body, 'Failed to transfer namespaced lease');
        return K8ClientLease.fromV1Lease(result.body);
    }
    /**
     * @param response - response object from the kubeclient call
     * @param error - body of the response becomes the error if the status is not OK
     * @param errorMessage - the error message to be passed in case it fails
     *
     * @throws SoloError - if the status code is not OK
     */
    handleKubernetesClientError(response, error, errorMessage) {
        const statusCode = +response?.statusCode || StatusCodes.INTERNAL_SERVER_ERROR;
        if (statusCode <= StatusCodes.ACCEPTED) {
            return;
        }
        errorMessage += `, statusCode: ${statusCode}`;
        this.logger.error(errorMessage, error);
        throw new SoloError(errorMessage, errorMessage, { statusCode: statusCode });
    }
}
//# sourceMappingURL=k8-client-leases.js.map