import { UMB_PROPERTY_DATASET_CONTEXT } from '../../property-dataset/index.js';
import { UMB_PROPERTY_CONTEXT } from './property.context-token.js';
import { UmbContextBase } from '../../../../../libs/class-api/index.js';
import { UmbArrayState, UmbBasicState, UmbClassState, UmbDeepState, UmbObjectState, UmbStringState, } from '../../../../../libs/observable-api/index.js';
import { UmbPropertyEditorConfigCollection } from '../../../property-editor/index.js';
import { UmbReadOnlyStateManager } from '../../../utils/index.js';
export class UmbPropertyContext extends UmbContextBase {
    #alias;
    #label;
    #description;
    #appearance;
    #value;
    #configValues;
    #config;
    #validation;
    #dataPath;
    #editor;
    #editorManifest;
    #editorDataSourceAlias;
    /**
     * Set the property editor UI element for this property.
     * @param {UmbPropertyEditorUiElement | undefined} editorElement The property editor UI element
     */
    setEditor(editorElement) {
        this.#editor.setValue(editorElement ?? undefined);
    }
    /**
     * Get the property editor UI element for this property.
     * @returns {UmbPropertyEditorUiElement | undefined} The property editor UI element
     */
    getEditor() {
        return this.#editor.getValue();
    }
    /**
     * Set the property editor manifest for this property.
     * @param {ManifestPropertyEditorUi | undefined} manifest The property editor manifest
     */
    setEditorManifest(manifest) {
        this.#editorManifest.setValue(manifest ?? undefined);
    }
    /**
     * Get the property editor manifest for this property.
     * @returns {UmbPropertyEditorUiElement | undefined} The property editor manifest
     */
    getEditorManifest() {
        return this.#editorManifest.getValue();
    }
    /**
     * Set the editor data source alias for this property.
     * @param {string | undefined} dataSourceAlias The data source alias to set
     */
    setEditorDataSourceAlias(dataSourceAlias) {
        this.#editorDataSourceAlias.setValue(dataSourceAlias ?? undefined);
    }
    /**
     * Get the editor data source alias for this property.
     * @returns {string | undefined} The editor data source alias for this property.
     */
    getEditorDataSourceAlias() {
        return this.#editorDataSourceAlias.getValue();
    }
    // property variant ID:
    #variantId;
    #variantDifference;
    #datasetContext;
    constructor(host) {
        super(host, UMB_PROPERTY_CONTEXT);
        this.#alias = new UmbStringState(undefined);
        this.alias = this.#alias.asObservable();
        this.#label = new UmbStringState(undefined);
        this.label = this.#label.asObservable();
        this.#description = new UmbStringState(undefined);
        this.description = this.#description.asObservable();
        this.#appearance = new UmbObjectState(undefined);
        this.appearance = this.#appearance.asObservable();
        this.#value = new UmbDeepState(undefined);
        this.value = this.#value.asObservable();
        this.#configValues = new UmbArrayState([], (x) => x.alias);
        this.configValues = this.#configValues.asObservable();
        this.#config = new UmbClassState(undefined);
        this.config = this.#config.asObservable();
        this.#validation = new UmbObjectState(undefined);
        this.validation = this.#validation.asObservable();
        this.validationMandatory = this.#validation.asObservablePart((x) => x?.mandatory);
        this.validationMandatoryMessage = this.#validation.asObservablePart((x) => x?.mandatoryMessage);
        this.#dataPath = new UmbStringState(undefined);
        this.dataPath = this.#dataPath.asObservable();
        this.#editor = new UmbBasicState(undefined);
        this.editor = this.#editor.asObservable();
        this.#editorManifest = new UmbBasicState(undefined);
        this.editorManifest = this.#editorManifest.asObservable();
        this.#editorDataSourceAlias = new UmbStringState(undefined);
        this.editorDataSourceAlias = this.#editorDataSourceAlias.asObservable();
        this.readOnlyState = new UmbReadOnlyStateManager(this);
        this.isReadOnly = this.readOnlyState.isReadOnly;
        // property variant ID:
        this.#variantId = new UmbClassState(undefined);
        this.variantId = this.#variantId.asObservable();
        this.#variantDifference = new UmbStringState(undefined);
        this.variantDifference = this.#variantDifference.asObservable();
        this.consumeContext(UMB_PROPERTY_DATASET_CONTEXT, (context) => {
            this.#datasetContext = context;
            this.setVariantId(context?.getVariantId?.());
            this._generateVariantDifferenceString();
            this._observeProperty();
        });
        this.observe(this.alias, () => {
            this._observeProperty();
        }, null);
        this.observe(this.configValues, (configValues) => {
            this.#config.setValue(configValues ? new UmbPropertyEditorConfigCollection(configValues) : undefined);
        }, null);
        this.observe(this.variantId, () => {
            this._generateVariantDifferenceString();
        }, null);
    }
    async _observeProperty() {
        const alias = this.#alias.getValue();
        if (!this.#datasetContext || !alias)
            return;
        this.observe(await this.#datasetContext.propertyVariantId?.(alias), (variantId) => {
            this.#variantId.setValue(variantId);
        }, 'observeVariantId');
        this.observe(await this.#datasetContext.propertyValueByAlias(alias), (value) => {
            this.#value.setValue(value);
        }, 'observeValue');
        this.observe(this.#datasetContext.readOnly, (value) => {
            const unique = 'UMB_DATASET';
            if (value) {
                this.readOnlyState.addState({
                    unique,
                });
            }
            else {
                this.readOnlyState.removeState(unique);
            }
        });
    }
    _generateVariantDifferenceString() {
        if (!this.#datasetContext)
            return;
        const contextVariantId = this.#datasetContext.getVariantId?.() ?? undefined;
        const propertyVariantId = this.#variantId.getValue();
        let shareMessage;
        if (contextVariantId && propertyVariantId) {
            // If on a Segment viewing a segment-shared property:
            // TODO: Do not use the content variant id, but know wether the property is configured to vary by segment.
            // Because we can view a default segment, then we do not know if the property is shared or not. [NL]
            if (contextVariantId.segment !== null && propertyVariantId.segment === null) {
                // If the property does not have culture, then we know this also will be shared across cultures.
                if (propertyVariantId.culture === null) {
                    shareMessage = 'content_sharedAcrossCultures';
                }
                else {
                    // If not, then we know it will be only be shared across segments.
                    shareMessage = 'content_sharedAcrossSegments';
                }
            }
            // TODO: Do not use the content variant id, but know wether the property is configured to vary by culture. (this is first a problem when we introduce the invariant-variant)
            if (contextVariantId.culture !== null && propertyVariantId.culture === null) {
                // If the property does have segment, then we know this will be shared across cultures and not across segments.
                if (propertyVariantId.segment !== null) {
                    shareMessage = 'content_sharedAcrossCultures';
                }
                else {
                    // if not then we know it's shared across everything.
                    shareMessage = 'content_shared';
                }
            }
        }
        this.#variantDifference.setValue(shareMessage);
    }
    /**
     * Set the alias of this property.
     * @param {string | undefined} alias - The alias of the property
     * @memberof UmbPropertyContext
     */
    setAlias(alias) {
        this.#alias.setValue(alias);
    }
    /**
     * Get the alias of this property.
     * @returns {*}  {(string | undefined)}
     * @memberof UmbPropertyContext
     */
    getAlias() {
        return this.#alias.getValue();
    }
    /**
     * Set the label of this property.
     * @param {(string | undefined)} label - The label of the property
     * @memberof UmbPropertyContext
     */
    setLabel(label) {
        this.#label.setValue(label);
    }
    /**
     * Get the label of this property.
     * @returns {(string | undefined)} - the label
     * @memberof UmbPropertyContext
     */
    getLabel() {
        return this.#label.getValue();
    }
    /**
     * Set the description of this property.
     * @param {(string | undefined)} description
     * @memberof UmbPropertyContext
     */
    setDescription(description) {
        this.#description.setValue(description);
    }
    /**
     * Get the description of this property.
     * @returns {*}  {(string | undefined)}
     * @memberof UmbPropertyContext
     */
    getDescription() {
        return this.#description.getValue();
    }
    /**
     * Set the appearance of this property.
     * @param {UmbPropertyTypeAppearanceModel | undefined} appearance - the appearance properties of this property
     * @memberof UmbPropertyContext
     */
    setAppearance(appearance) {
        this.#appearance.setValue(appearance);
    }
    /**
     * Get the appearance of this property.
     * @returns {UmbPropertyTypeAppearanceModel | undefined}- the appearance properties of this property
     * @memberof UmbPropertyContext
     */
    getAppearance() {
        return this.#appearance.getValue();
    }
    /**
     * Set the value of this property.
     * @param {unknown} value - the whole value to be set
     */
    setValue(value) {
        const alias = this.#alias.getValue();
        if (!this.#datasetContext || !alias)
            return;
        this.#datasetContext?.setPropertyValue(alias, value);
    }
    /**
     * Gets the current value of this property.
     * Notice this is not reactive, you should us the `value` observable for that.
     * @returns {unknown} - the current value of this property
     */
    getValue() {
        return this.#value.getValue();
    }
    /**
     * Set the config of this property.
     * @param {Array<UmbPropertyEditorConfigProperty> | undefined} config - Array of configurations for this property
     * @memberof UmbPropertyContext
     */
    setConfig(config) {
        this.#configValues.setValue(config ?? []);
    }
    /**
     * Get the config of this property.
     * @returns {Array<UmbPropertyEditorConfigProperty> | undefined} - Array of configurations for this property
     * @memberof UmbPropertyContext
     */
    getConfig() {
        return this.#configValues.getValue();
    }
    /**
     * Set the variant ID of this property.
     * @param {UmbVariantId | undefined} variantId - The property Variant ID, not necessary the same as the Property Dataset Context VariantId.
     * @memberof UmbPropertyContext
     */
    setVariantId(variantId) {
        this.#variantId.setValue(variantId);
    }
    /**
     * Get the variant ID of this property.
     * @returns {UmbVariantId | undefined} - The property Variant ID, not necessary the same as the Property Dataset Context VariantId.
     * @memberof UmbPropertyContext
     */
    getVariantId() {
        return this.#variantId.getValue();
    }
    /**
     * Set the validation of this property.
     * @param {UmbPropertyTypeValidationModel | undefined} validation - Object holding the Validation Properties.
     * @memberof UmbPropertyContext
     */
    setValidation(validation) {
        this.#validation.setValue(validation);
    }
    /**
     * Get the validation of this property.
     * @returns {UmbPropertyTypeValidationModel | undefined} - Object holding the Validation Properties.
     * @memberof UmbPropertyContext
     */
    getValidation() {
        return this.#validation.getValue();
    }
    /**
     * Get the read only state of this property
     * @returns {boolean} - If property is in read-only mode.
     * @memberof UmbPropertyContext
     */
    getIsReadOnly() {
        return this.readOnlyState.getIsReadOnly();
    }
    setDataPath(dataPath) {
        this.#dataPath.setValue(dataPath);
    }
    getDataPath() {
        return this.#dataPath.getValue();
    }
    /**
     * Reset the value of this property.
     * @memberof UmbPropertyContext
     */
    resetValue() {
        this.setValue(undefined); // TODO: We should get the value from the server aka. the value from the persisted data. (Most workspaces holds this data, via dataset) [NL]
    }
    /**
     * Clear the value of this property.
     * @memberof UmbPropertyContext
     */
    clearValue() {
        this.setValue(undefined); // TODO: We should get the default value from Property Editor maybe even later the DocumentType, as that would hold the default value for the property. (Get it via the dataset) [NL]
    }
    destroy() {
        super.destroy();
        this.#alias.destroy();
        this.#label.destroy();
        this.#description.destroy();
        this.#appearance.destroy();
        this.#configValues.destroy();
        this.#value.destroy();
        this.#config.destroy();
        this.#datasetContext = undefined;
    }
}
