/*
 * Copyright (c) 2023-2025 Datalayer, Inc.
 * Distributed under the terms of the Modified BSD License.
 */
/**
 * Space domain model for the Datalayer Client.
 *
 * @module models/SpaceDTO
 */
import * as users from '../api/spacer/users.js';
import * as items from '../api/spacer/items.js';
import * as notebooks from '../api/spacer/notebooks.js';
import * as lexicals from '../api/spacer/lexicals.js';
import { NotebookDTO } from './NotebookDTO.js';
import { LexicalDTO } from './LexicalDTO.js';
import { ItemTypes } from '../client/constants.js';
import { convertSpaceItemsToModels } from '../client/utils/spacerUtils.js';
import { validateJSON } from '../api/utils/validation.js';
/**
 * Space domain model that wraps API responses with convenient methods.
 * Provides workspace management with data refresh and content creation operations.
 *
 * @example
 * ```typescript
 * const space = spaces[0];
 * const items = await space.getItems();
 * const notebook = await space.createNotebook({ name: 'Analysis' });
 * ```
 */
export class SpaceDTO {
    _data;
    _client;
    _items = null;
    _deleted = false;
    /**
     * Create a Space instance.
     *
     * @param data - Space data from API
     * @param client - Client instance
     */
    constructor(data, client) {
        this._data = data;
        this._client = client;
    }
    // ========================================================================
    // Helper Methods
    // ========================================================================
    /**
     * Check if this space has been deleted and throw error if so.
     * @throws Error if deleted
     */
    _checkDeleted() {
        if (this._deleted) {
            throw new Error(`Space ${this._data.uid} has been deleted and no longer exists`);
        }
    }
    /**
     * Refresh space data from the API by fetching user's spaces.
     */
    async refresh() {
        const token = this._client.getToken();
        const spacerRunUrl = this._client.getSpacerRunUrl();
        const response = await users.getMySpaces(token, spacerRunUrl);
        const freshSpace = response.spaces.find(s => s.uid === this.uid);
        if (freshSpace) {
            this._data = freshSpace;
        }
    }
    // ========================================================================
    // Static Properties (set at creation, never change)
    // ========================================================================
    /** Unique identifier for the space. */
    get uid() {
        this._checkDeleted();
        return this._data.uid;
    }
    /** URL-friendly handle for the space. */
    get handle() {
        this._checkDeleted();
        return this._data.handle_s;
    }
    /** Space variant type. */
    get variant() {
        this._checkDeleted();
        return this._data.variant_s;
    }
    /**
     * The name of the space.
     */
    get name() {
        return this._data.name_t;
    }
    /**
     * The description of the space.
     */
    get description() {
        return this._data.description_t;
    }
    // ========================================================================
    // Space-specific Methods
    // ========================================================================
    /**
     * Helper method to create items in this space.
     *
     * @param itemType - Type of item to create
     * @param data - Creation configuration
     * @returns Created model instance
     * @internal
     */
    async _createItem(data) {
        this._checkDeleted();
        // Get necessary configuration from Client
        const token = this._client.getToken();
        const spacerRunUrl = this._client.getSpacerRunUrl();
        if (data.type === ItemTypes.NOTEBOOK) {
            const requestData = {
                spaceId: this.uid,
                name: data.name,
                description: data.description,
                notebookType: data.type,
                file: data.file,
            };
            const response = await notebooks.createNotebook(token, requestData, spacerRunUrl);
            if (!response.notebook) {
                throw new Error('Failed to create notebook: No notebook returned');
            }
            else {
                return new NotebookDTO(response.notebook, this._client);
            }
        }
        else if (data.type === ItemTypes.LEXICAL) {
            const requestData = {
                spaceId: this.uid,
                name: data.name,
                description: data.description,
                documentType: data.type,
                file: data.file,
            };
            const response = await lexicals.createLexical(token, requestData, spacerRunUrl);
            if (!response.document) {
                throw new Error('Failed to create lexical document: No document returned');
            }
            else {
                return new LexicalDTO(response.document, this._client);
            }
        }
        else {
            throw new Error(`Unsupported item type: ${data.type}`);
        }
    }
    /**
     * Get all items in this space as model instances.
     *
     * @returns Array of Notebook and Lexical model instances
     */
    async getItems() {
        this._checkDeleted();
        const token = this._client.getToken();
        const spacerRunUrl = this._client.getSpacerRunUrl();
        const response = await items.getSpaceItems(token, this.uid, spacerRunUrl);
        // Use shared utility function to convert items to model instances
        this._items = convertSpaceItemsToModels(response.items || [], this._client);
        return this._items;
    }
    /**
     * Create a new notebook in this space.
     *
     * @param data - Notebook creation configuration
     * @returns Created Notebook instance
     */
    async createNotebook(data) {
        return this._createItem({
            name: data.name,
            type: ItemTypes.NOTEBOOK,
            description: data.description,
            file: data.file,
        });
    }
    /**
     * Create a new lexical document in this space.
     *
     * @param data - Lexical creation configuration
     * @returns Created Lexical instance
     */
    async createLexical(data) {
        return this._createItem({
            name: data.name,
            type: ItemTypes.LEXICAL,
            description: data.description,
            file: data.file,
        });
    }
    // ========================================================================
    // Utility Methods
    // ========================================================================
    /**
     * Get raw space data object.
     * Returns cached data without refreshing.
     *
     * @returns Raw space data object
     */
    /**
     * Get space data in camelCase format.
     * Returns only the core fields that consumers need.
     * This provides a stable interface regardless of API changes.
     *
     * @returns Core space data with camelCase properties
     */
    toJSON() {
        this._checkDeleted();
        const obj = {
            uid: this.uid,
            name: this.name,
            description: this.description,
            variant: this.variant,
            handle: this.handle,
            items: this._data.items
                ? convertSpaceItemsToModels(this._data.items, this._client).map(item => item.toJSON())
                : [],
        };
        validateJSON(obj, 'Space');
        return obj;
    }
    /**
     * Get the raw space data exactly as received from the API.
     * This preserves the original snake_case naming from the API response.
     *
     * @returns Raw space data from API
     */
    rawData() {
        this._checkDeleted();
        return this._data;
    }
    /** String representation of the space. */
    toString() {
        this._checkDeleted();
        return `Space(${this.uid}, ${this.name})`;
    }
}
