/*
 * Copyright (c) 2023-2025 Datalayer, Inc.
 * Distributed under the terms of the Modified BSD License.
 */
/**
 * Runtimes mixin for managing computational environments and runtime instances.
 * @module client/mixins/RuntimesMixin
 */
import * as environments from '../../api/runtimes/environments.js';
import * as runtimes from '../../api/runtimes/runtimes.js';
import * as snapshots from '../../api/runtimes/snapshots.js';
import { EnvironmentDTO } from '../../models/EnvironmentDTO.js';
import { RuntimeDTO } from '../../models/RuntimeDTO.js';
import { RuntimeSnapshotDTO } from '../../models/RuntimeSnapshotDTO.js';
import { HealthCheck } from '../../models/HealthCheck.js';
/** Runtimes mixin providing computational environment and runtime management. */
export function RuntimesMixin(Base) {
    return class extends Base {
        // ========================================================================
        // Helper Functions
        // ========================================================================
        _extractRuntimePodName(runtimePodNameOrInstance) {
            return typeof runtimePodNameOrInstance === 'string'
                ? runtimePodNameOrInstance
                : runtimePodNameOrInstance.podName;
        }
        _extractSnapshotId(snapshotIdOrInstance) {
            return typeof snapshotIdOrInstance === 'string'
                ? snapshotIdOrInstance
                : snapshotIdOrInstance.uid;
        }
        // ========================================================================
        // Environments
        // ========================================================================
        /**
         * List all available computational environments.
         * @returns Array of Environment model instances
         */
        async listEnvironments() {
            const token = this.getToken();
            const runtimesRunUrl = this.getRuntimesRunUrl();
            const response = await environments.listEnvironments(token, runtimesRunUrl);
            // Save for later use after first call
            this.environments = response.environments.map(env => new EnvironmentDTO(env, this));
            return this.environments;
        }
        // ========================================================================
        // Runtimes
        // ========================================================================
        /**
         * Create a new computational runtime.
         * @param environmentName - Name of the environment to use
         * @param type - Type of runtime
         * @param givenName - User-friendly name for the runtime
         * @param creditsLimit - Credits limit
         * @returns Created runtime
         */
        async createRuntime(environmentName, type, givenName, minutesLimit, fromSnapshotId) {
            if (!this.environments) {
                await this.listEnvironments();
            }
            if (this.environments) {
                const env = this.environments.find((e) => e.name === environmentName);
                if (!env) {
                    throw new Error(`Environment "${environmentName}" not found. Available environments: ${this.environments.map((e) => e.name).join(', ')}`);
                }
                else {
                    const token = this.getToken();
                    const runtimesRunUrl = this.getRuntimesRunUrl();
                    const creditsLimit = this.calculateCreditsFromMinutes(minutesLimit, env.burningRate);
                    const data = {
                        environment_name: environmentName,
                        type,
                        given_name: givenName,
                        credits_limit: creditsLimit,
                        from: fromSnapshotId,
                    };
                    const response = await runtimes.createRuntime(token, data, runtimesRunUrl);
                    return new RuntimeDTO(response.runtime, this);
                }
            }
            else {
                throw new Error('Environments not loaded');
            }
        }
        /**
         * List all runtimes.
         * @returns Array of runtimes
         */
        async listRuntimes() {
            const token = this.getToken();
            const runtimesRunUrl = this.getRuntimesRunUrl();
            const response = await runtimes.listRuntimes(token, runtimesRunUrl);
            return response.runtimes.map(r => new RuntimeDTO(r, this));
        }
        /**
         * Get details for a specific runtime by pod name.
         * @param podName - Runtime pod name
         * @returns Runtime details
         */
        async getRuntime(podName) {
            const token = this.getToken();
            const runtimesRunUrl = this.getRuntimesRunUrl();
            const runtimeData = await runtimes.getRuntime(token, podName, runtimesRunUrl);
            return new RuntimeDTO(runtimeData, this);
        }
        /**
         * Delete a runtime permanently.
         * @param podName - Runtime pod name
         */
        async deleteRuntime(podName) {
            const token = this.getToken();
            const runtimesRunUrl = this.getRuntimesRunUrl();
            await runtimes.deleteRuntime(token, podName, runtimesRunUrl);
        }
        /**
         * Terminate all runtimes.
         * Lists all runtimes and deletes them in parallel.
         * @returns Array of results for each deletion (fulfilled or rejected)
         */
        async terminateAllRuntimes() {
            const token = this.getToken();
            const runtimesRunUrl = this.getRuntimesRunUrl();
            // List all runtimes
            const response = await runtimes.listRuntimes(token, runtimesRunUrl);
            // Delete all runtimes in parallel
            const deletePromises = response.runtimes.map(runtime => runtimes.deleteRuntime(token, runtime.pod_name, runtimesRunUrl));
            return Promise.allSettled(deletePromises);
        }
        // ========================================================================
        // Snapshots
        // ========================================================================
        /**
         * Create a snapshot of a runtime.
         * @param podName - Pod name of the runtime to snapshot
         * @param name - Name for the snapshot
         * @param description - Description of the snapshot
         * @param stop - Whether to stop the runtime after creating snapshot (defaults to false)
         * @returns Created snapshot
         */
        async createSnapshot(podName, name, description, stop = false) {
            const token = this.getToken();
            const runtimesRunUrl = this.getRuntimesRunUrl();
            const data = {
                pod_name: podName,
                name,
                description,
                stop,
            };
            const response = await snapshots.createSnapshot(token, data, runtimesRunUrl);
            return new RuntimeSnapshotDTO(response.snapshot, this);
        }
        /**
         * List all runtime snapshots.
         * @returns Array of snapshots
         */
        async listSnapshots() {
            const token = this.getToken();
            const runtimesRunUrl = this.getRuntimesRunUrl();
            const response = await snapshots.listSnapshots(token, runtimesRunUrl);
            return response.snapshots.map(s => new RuntimeSnapshotDTO(s, this));
        }
        /**
         * Get details for a specific snapshot by ID.
         * @param id - Snapshot ID
         * @returns Snapshot details
         */
        async getSnapshot(id) {
            const token = this.getToken();
            const runtimesRunUrl = this.getRuntimesRunUrl();
            const response = await snapshots.getSnapshot(token, id, runtimesRunUrl);
            return new RuntimeSnapshotDTO(response.snapshot, this);
        }
        /**
         * Delete a snapshot permanently.
         * @param id - Snapshot ID
         */
        async deleteSnapshot(id) {
            const token = this.getToken();
            const runtimesRunUrl = this.getRuntimesRunUrl();
            await snapshots.deleteSnapshot(token, id, runtimesRunUrl);
        }
        // ========================================================================
        // Service Health Checks
        // ========================================================================
        /**
         * Check the health status of the Runtimes service.
         * @returns Health check result with status and response time
         */
        async checkRuntimesHealth() {
            const startTime = Date.now();
            const errors = [];
            let status = 'unknown';
            let healthy = false;
            try {
                // Test basic connectivity by listing environments (lightweight operation)
                const environments = await this.listEnvironments();
                const responseTime = Date.now() - startTime;
                if (Array.isArray(environments)) {
                    healthy = true;
                    status = 'operational';
                }
                else {
                    status = 'degraded';
                    errors.push('Unexpected response format from environments endpoint');
                }
                return new HealthCheck({
                    healthy,
                    status,
                    responseTime,
                    errors,
                    timestamp: new Date(),
                }, this);
            }
            catch (error) {
                const responseTime = Date.now() - startTime;
                status = 'down';
                errors.push(`Service unreachable: ${error}`);
                return new HealthCheck({
                    healthy: false,
                    status,
                    responseTime,
                    errors,
                    timestamp: new Date(),
                }, this);
            }
        }
    };
}
