import { UMB_DOCUMENT_ENTITY_TYPE } from '../../entity.js';
import { DocumentService } from '../../../../core/backend-api/index.js';
import { tryExecute } from '../../../../core/resources/index.js';
/**
 * A server data source for Document publishing
 * @class UmbDocumentPublishingServerDataSource
 * @implements {DocumentTreeDataSource}
 */
export class UmbDocumentPublishingServerDataSource {
    #host;
    /**
     * Creates an instance of UmbDocumentPublishingServerDataSource.
     * @param {UmbControllerHost} host - The controller host for this controller to be appended to
     * @memberof UmbDocumentPublishingServerDataSource
     */
    constructor(host) {
        this.#host = host;
    }
    /**
     * Publish one or more variants of a Document
     * @param {string} unique
     * @param {Array<UmbVariantId>} variantIds
     * @param variants
     * @returns {*}
     * @memberof UmbDocumentPublishingServerDataSource
     */
    async publish(unique, variants) {
        if (!unique)
            throw new Error('Id is missing');
        const publishSchedules = variants.map((variant) => {
            return {
                culture: variant.variantId.isCultureInvariant() ? null : variant.variantId.toCultureString(),
                schedule: variant.schedule,
            };
        });
        // TODO: THIS DOES NOT TAKE SEGMENTS INTO ACCOUNT!!!!!!
        const body = {
            publishSchedules,
        };
        return tryExecute(this.#host, DocumentService.putDocumentByIdPublish({ path: { id: unique }, body: body }));
    }
    /**
     * Unpublish one or more variants of a Document
     * @param {string} unique
     * @param {Array<UmbVariantId>} variantIds
     * @returns {*}
     * @memberof UmbDocumentPublishingServerDataSource
     */
    async unpublish(unique, variantIds) {
        if (!unique)
            throw new Error('Id is missing');
        // TODO: THIS DOES NOT TAKE SEGMENTS INTO ACCOUNT!!!!!!
        // If variants are culture invariant, we need to pass null to the API
        const hasInvariant = variantIds.some((variant) => variant.isCultureInvariant());
        if (hasInvariant) {
            const body = {
                cultures: null,
            };
            return tryExecute(this.#host, DocumentService.putDocumentByIdUnpublish({ path: { id: unique }, body: body }));
        }
        const body = {
            cultures: variantIds.map((variant) => variant.toCultureString()),
        };
        return tryExecute(this.#host, DocumentService.putDocumentByIdUnpublish({ path: { id: unique }, body: body }));
    }
    /**
     * Publish variants of a document and all its descendants
     * @param unique
     * @param variantIds
     * @param includeUnpublishedDescendants
     * @memberof UmbDocumentPublishingServerDataSource
     */
    async publishWithDescendants(unique, variantIds, includeUnpublishedDescendants) {
        if (!unique)
            throw new Error('Id is missing');
        const body = {
            cultures: variantIds.map((variant) => variant.toCultureString()),
            includeUnpublishedDescendants,
        };
        // Initiate the publish descendants task and get back a task Id.
        const { data, error } = await tryExecute(this.#host, DocumentService.putDocumentByIdPublishWithDescendants({ path: { id: unique }, body: body }));
        if (error || !data) {
            return { error };
        }
        const taskId = data.taskId;
        // Poll until we know publishing is finished, then return the result.
        let isFirstPoll = true;
        while (true) {
            await new Promise((resolve) => setTimeout(resolve, isFirstPoll ? 1000 : 5000));
            isFirstPoll = false;
            const { data, error } = await tryExecute(this.#host, DocumentService.getDocumentByIdPublishWithDescendantsResultByTaskId({ path: { id: unique, taskId } }));
            if (error || !data) {
                return { error };
            }
            if (data.isComplete) {
                return { error: null };
            }
        }
    }
    /**
     * Get the published Document by its unique
     * @param {string} unique - Document unique
     * @returns {Promise<UmbDataSourceResponse<UmbDocumentDetailModel>>} Published document
     * @memberof UmbDocumentPublishingServerDataSource
     */
    async published(unique) {
        if (!unique)
            throw new Error('Unique is missing');
        const { data, error } = await tryExecute(this.#host, DocumentService.getDocumentByIdPublished({ path: { id: unique } }));
        if (error || !data) {
            return { error };
        }
        // TODO: make data mapper to prevent errors
        const document = {
            entityType: UMB_DOCUMENT_ENTITY_TYPE,
            unique: data.id,
            values: data.values.map((value) => {
                return {
                    editorAlias: value.editorAlias,
                    culture: value.culture || null,
                    segment: value.segment || null,
                    alias: value.alias,
                    value: value.value,
                };
            }),
            variants: data.variants.map((variant) => {
                return {
                    culture: variant.culture || null,
                    segment: variant.segment || null,
                    state: variant.state,
                    name: variant.name,
                    publishDate: variant.publishDate || null,
                    createDate: variant.createDate,
                    updateDate: variant.updateDate,
                    scheduledPublishDate: variant.scheduledPublishDate || null,
                    scheduledUnpublishDate: variant.scheduledUnpublishDate || null,
                    flags: variant.flags,
                };
            }),
            template: data.template ? { unique: data.template.id } : null,
            documentType: {
                unique: data.documentType.id,
                collection: data.documentType.collection ? { unique: data.documentType.collection.id } : null,
                icon: data.documentType.icon,
            },
            isTrashed: data.isTrashed,
            flags: data.flags,
        };
        return { data: document };
    }
}
