import { UmbDocumentVariantState } from '../types.js';
import { UmbControllerBase } from '../../../../libs/class-api/index.js';
import { UmbArrayState, UmbBasicState, UmbBooleanState, UmbObjectState, UmbStringState, } from '../../../../libs/observable-api/index.js';
import { UMB_VARIANT_CONTEXT } from '../../../core/variant/index.js';
/**
 *
 * @param variants
 */
function isVariantsInvariant(variants) {
    return variants?.[0]?.culture === null;
}
/**
 *
 * @param variants
 * @param culture
 */
function findVariant(variants, culture) {
    return variants.find((x) => x.culture === culture);
}
/**
 * A controller for resolving data for a document item
 * @exports
 * @class UmbDocumentItemDataResolver
 * @augments {UmbControllerBase}
 */
export class UmbDocumentItemDataResolver extends UmbControllerBase {
    #data;
    #name;
    #state;
    #isDraft;
    #createDate;
    #updateDate;
    #flags;
    #variantContext;
    #fallbackCulture;
    #displayCulture;
    constructor(host) {
        super(host);
        this.#data = new UmbObjectState(undefined);
        this.entityType = this.#data.asObservablePart((x) => x?.entityType);
        this.unique = this.#data.asObservablePart((x) => x?.unique);
        this.icon = this.#data.asObservablePart((x) => x?.documentType.icon);
        this.typeUnique = this.#data.asObservablePart((x) => x?.documentType.unique);
        this.isTrashed = this.#data.asObservablePart((x) => x?.isTrashed);
        this.hasCollection = this.#data.asObservablePart((x) => !!x?.documentType.collection);
        this.#name = new UmbStringState(undefined);
        this.name = this.#name.asObservable();
        this.#state = new UmbStringState(undefined);
        this.state = this.#state.asObservable();
        this.#isDraft = new UmbBooleanState(undefined);
        this.isDraft = this.#isDraft.asObservable();
        this.#createDate = new UmbBasicState(undefined);
        this.createDate = this.#createDate.asObservable();
        this.#updateDate = new UmbBasicState(undefined);
        this.updateDate = this.#updateDate.asObservable();
        this.#flags = new UmbArrayState([], (data) => data.alias);
        this.flags = this.#flags.asObservable();
        this.consumeContext(UMB_VARIANT_CONTEXT, (context) => {
            this.#variantContext = context;
            this.#observeVariantContext();
        });
    }
    #observeVariantContext() {
        this.observe(this.#variantContext?.displayCulture, (displayCulture) => {
            if (displayCulture === undefined)
                return;
            this.#displayCulture = displayCulture;
            this.#setVariantAwareValues();
        }, 'umbObserveVariantId');
        this.observe(this.#variantContext?.fallbackCulture, (fallbackCulture) => {
            if (fallbackCulture === undefined)
                return;
            this.#fallbackCulture = fallbackCulture;
            this.#setVariantAwareValues();
        }, 'umbObserveFallbackCulture');
    }
    /**
     * Get the display culture or fallback culture
     * @returns {string | null | undefined} The display culture or fallback culture
     * @memberof UmbDocumentItemDataResolver
     */
    getCulture() {
        return this.#displayCulture || this.#fallbackCulture;
    }
    /**
     * Get the current item
     * @returns {DocumentItemModel | undefined} The current item
     * @memberof UmbDocumentItemDataResolver
     */
    getData() {
        return this.#data.getValue();
    }
    /**
     * Set the current item
     * @param {DocumentItemModel | undefined} data The current item
     * @memberof UmbDocumentItemDataResolver
     */
    setData(data) {
        this.#data.setValue(data);
        this.#setVariantAwareValues();
    }
    /**
     * Get the entity type of the item
     * @returns {Promise<string | undefined>} The entity type of the item
     * @memberof UmbDocumentItemDataResolver
     */
    async getEntityType() {
        return await this.observe(this.entityType).asPromise();
    }
    /**
     * Get the unique of the item
     * @returns {Promise<string | undefined>} The unique of the item
     * @memberof UmbDocumentItemDataResolver
     */
    async getUnique() {
        return await this.observe(this.unique).asPromise();
    }
    /**
     * Get the name of the item
     * @returns {Promise<string>} The name of the item
     * @memberof UmbDocumentItemDataResolver
     */
    async getName() {
        return (await this.observe(this.name).asPromise()) || '';
    }
    /**
     * Get the icon of the item
     * @returns {Promise<string | undefined>} The icon of the item
     * @memberof UmbDocumentItemDataResolver
     */
    async getIcon() {
        return await this.observe(this.icon).asPromise();
    }
    /**
     * Get the state of the item
     * @returns {Promise<string | undefined>} The state of the item
     * @memberof UmbDocumentItemDataResolver
     */
    async getState() {
        return await this.observe(this.state).asPromise();
    }
    /**
     * Get the isDraft of the item
     * @returns {Promise<boolean>} The isDraft of the item
     * @memberof UmbDocumentItemDataResolver
     */
    async getIsDraft() {
        return (await this.observe(this.isDraft).asPromise()) ?? false;
    }
    /**
     * Get the isTrashed of the item
     * @returns {Promise<boolean | undefined>} The isTrashed of the item
     * @memberof UmbDocumentItemDataResolver
     */
    async getIsTrashed() {
        return (await this.observe(this.isTrashed).asPromise()) ?? false;
    }
    /**
     * Get the create date of the item
     * @returns {Promise<Date>} The create date of the item
     * @memberof UmbDocumentItemDataResolver
     */
    async getCreateDate() {
        return (await this.observe(this.createDate).asPromise()) || undefined;
    }
    /**
     * Get the update date of the item
     * @returns {Promise<Date>} The update date of the item
     * @memberof UmbDocumentItemDataResolver
     */
    async getUpdateDate() {
        return (await this.observe(this.updateDate).asPromise()) || undefined;
    }
    /**
     * Test if the item has a collection
     * @returns {boolean} Boolean of whether the item has a collection.
     * @memberof UmbDocumentItemDataResolver
     */
    getHasCollection() {
        return this.getData()?.documentType.collection != undefined;
    }
    #setVariantAwareValues() {
        if (!this.#variantContext)
            return;
        if (!this.#displayCulture)
            return;
        if (!this.#fallbackCulture)
            return;
        if (!this.#data)
            return;
        this.#setName();
        this.#setIsDraft();
        this.#setState();
        this.#setCreateDate();
        this.#setUpdateDate();
        this.#setFlags();
    }
    #setName() {
        const variant = this.#getCurrentVariant();
        if (variant?.name) {
            this.#name.setValue(variant.name);
            return;
        }
        const variants = this.getData()?.variants;
        if (variants) {
            // Try fallback culture first, then first variant with any name
            const fallbackName = findVariant(variants, this.#fallbackCulture)?.name ?? variants.find((x) => x.name)?.name;
            if (fallbackName) {
                this.#name.setValue(`(${fallbackName})`);
                return;
            }
        }
        this.#name.setValue('(Untitled)');
    }
    #setIsDraft() {
        const variant = this.#getCurrentVariant();
        const isDraft = variant?.state === UmbDocumentVariantState.DRAFT || false;
        this.#isDraft.setValue(isDraft);
    }
    #setState() {
        const variant = this.#getCurrentVariant();
        const state = variant?.state || UmbDocumentVariantState.NOT_CREATED;
        this.#state.setValue(state);
    }
    async #setCreateDate() {
        const variant = await this.#getCurrentVariant();
        if (variant) {
            this.#createDate.setValue(variant.createDate);
            return;
        }
        const variants = this.getData()?.variants;
        if (variants) {
            const fallbackCreateDate = findVariant(variants, this.#fallbackCulture)?.createDate;
            this.#createDate.setValue(fallbackCreateDate);
        }
        else {
            this.#createDate.setValue(undefined);
        }
    }
    async #setUpdateDate() {
        const variant = await this.#getCurrentVariant();
        if (variant) {
            this.#updateDate.setValue(variant.updateDate);
            return;
        }
        const variants = this.getData()?.variants;
        if (variants) {
            const fallbackUpdateDate = findVariant(variants, this.#fallbackCulture)?.updateDate;
            this.#updateDate.setValue(fallbackUpdateDate);
        }
        else {
            this.#updateDate.setValue(undefined);
        }
    }
    #setFlags() {
        const data = this.getData();
        if (!data) {
            this.#flags.setValue([]);
            return;
        }
        const flags = data.flags ?? [];
        const variantFlags = this.#getCurrentVariant()?.flags ?? [];
        this.#flags.setValue([...flags, ...variantFlags]);
    }
    #getCurrentVariant() {
        const variants = this.getData()?.variants;
        if (!variants)
            return undefined;
        if (isVariantsInvariant(variants)) {
            return variants[0];
        }
        return findVariant(variants, this.#displayCulture);
    }
}
