/*
 * Copyright (c) 2023-2025 Datalayer, Inc.
 * Distributed under the terms of the Modified BSD License.
 */
/**
 * Credits model for the Datalayer Client.
 *
 * @module models/CreditsDTO
 */
import { validateJSON } from '../api/utils/validation.js';
/**
 * Credits model representing user's available credits and usage.
 *
 * @example
 * ```typescript
 * const credits = await client.getCredits();
 * console.log(`Available: ${credits.available}`);
 * console.log(`Quota: ${credits.quota || 'unlimited'}`);
 *
 * // Calculate maximum runtime for an environment
 * const maxMinutes = credits.calculateMaxRuntimeMinutes(environment.burningRate);
 * ```
 */
export class CreditsDTO {
    /** @internal */
    _data;
    _reservations;
    constructor(data, reservations = []) {
        this._data = data;
        this._reservations = reservations;
    }
    /**
     * Available credits for the user.
     */
    get available() {
        return this._data.credits;
    }
    /**
     * Credit quota for the user.
     * Returns null if unlimited.
     */
    get quota() {
        return this._data.quota;
    }
    /**
     * Last update timestamp.
     */
    get lastUpdate() {
        return this._data.last_update;
    }
    /**
     * Active credit reservations.
     */
    get reservations() {
        return [...this._reservations];
    }
    /**
     * Total reserved credits across all reservations.
     */
    get totalReserved() {
        return this._reservations.reduce((sum, r) => sum + r.credits, 0);
    }
    /**
     * Net available credits (available minus reserved).
     */
    get netAvailable() {
        return Math.max(0, this.available - this.totalReserved);
    }
    /**
     * Get runtime reservations (reservations that start with 'runtime-').
     */
    get runtimeReservations() {
        return this._reservations.filter(r => r.id.startsWith('runtime-'));
    }
    /**
     * Check if there are any active runtime reservations.
     */
    get hasActiveRuntimes() {
        return this.runtimeReservations.length > 0;
    }
    /**
     * Calculate maximum runtime in minutes based on environment burning rate.
     *
     * @param burningRate - Credits consumed per hour
     * @returns Maximum runtime in minutes
     */
    calculateMaxRuntimeMinutes(burningRate) {
        if (burningRate <= 0)
            return 0;
        const burningRatePerMinute = burningRate * 60;
        return Math.floor(this.netAvailable / burningRatePerMinute);
    }
    /**
     * Calculate credits needed for runtime duration.
     *
     * @param minutes - Runtime duration in minutes
     * @param burningRate - Credits consumed per hour
     * @returns Credits needed
     */
    calculateCreditsFromMinutes(minutes, burningRate) {
        const burningRatePerMinute = burningRate * 60;
        return minutes * burningRatePerMinute;
    }
    /**
     * Check if user has enough credits for runtime.
     *
     * @param minutes - Runtime duration in minutes
     * @param burningRate - Credits consumed per hour
     * @returns True if user has enough credits
     */
    hasEnoughCreditsForRuntime(minutes, burningRate) {
        const creditsNeeded = this.calculateCreditsFromMinutes(minutes, burningRate);
        return this.netAvailable >= creditsNeeded;
    }
    /**
     * Convert to JSON representation.
     */
    toJSON() {
        // FIXME
        const obj = {
            ...this._data,
            reservations: this._reservations,
        };
        validateJSON(obj, 'Credits');
        return obj;
    }
    /**
     * String representation of credits.
     */
    toString() {
        const quotaStr = this.quota !== null ? ` of ${this.quota}` : '';
        const reservedStr = this.totalReserved > 0 ? ` (${this.totalReserved} reserved)` : '';
        return `Credits: ${this.available}${quotaStr}${reservedStr}`;
    }
}
