var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { UmbPropertyContext } from './property.context.js';
import { css, customElement, html, property, state, nothing } from '../../../../../external/lit/index.js';
import { createExtensionElement, UmbExtensionsApiInitializer } from '../../../../../libs/extension-api/index.js';
import { umbExtensionsRegistry } from '../../../extension-registry/index.js';
import { UmbLitElement } from '../../../lit-element/index.js';
import { UmbTextStyles } from '../../../style/index.js';
import { UmbBindServerValidationToFormControl, UmbFormControlValidator, UmbObserveValidationStateController, } from '../../../validation/index.js';
import { UMB_MISSING_PROPERTY_EDITOR_UI_UI_ALIAS, } from '../../../property-editor/index.js';
import { UMB_MARK_ATTRIBUTE_NAME } from '../../../const/index.js';
import { UmbRoutePathAddendumContext } from '../../../router/index.js';
/**
 *  @element umb-property
 *  @description Component for displaying a property with editor from extension registry.
 *	The Element will render a Property Editor based on the Property Editor UI alias passed to the element.
 *  This will also render all Property Actions related to the Property Editor UI Alias.
 */
let UmbPropertyElement = class UmbPropertyElement extends UmbLitElement {
    /**
     * Label. Name of the property
     * @type {string}
     * @default
     */
    set label(label) {
        this.#propertyContext.setLabel(label);
    }
    get label() {
        return this.#propertyContext.getLabel();
    }
    /**
     * Description: render a description underneath the label.
     * @type {string}
     * @default
     */
    set description(description) {
        this.#propertyContext.setDescription(description);
    }
    get description() {
        return this.#propertyContext.getDescription();
    }
    /**
     * Appearance: Appearance settings for the property.
     */
    set appearance(appearance) {
        this.#propertyContext.setAppearance(appearance);
    }
    get appearance() {
        return this.#propertyContext.getAppearance();
    }
    /**
     * Alias
     * @public
     * @type {string}
     * @default
     */
    set alias(alias) {
        this.setAttribute(UMB_MARK_ATTRIBUTE_NAME, 'property:' + alias);
        this.#propertyContext.setAlias(alias);
    }
    get alias() {
        return this.#propertyContext.getAlias() ?? '';
    }
    /**
     * Property Editor UI Alias. Render the Property Editor UI registered for this alias.
     * @public
     * @type {string}
     * @default
     */
    set propertyEditorUiAlias(value) {
        this._propertyEditorUiAlias = value;
        this._observePropertyEditorUI();
    }
    get propertyEditorUiAlias() {
        return this._propertyEditorUiAlias ?? '';
    }
    set propertyEditorDataSourceAlias(value) {
        this.#propertyContext.setEditorDataSourceAlias(value);
        if (this._element) {
            this._element.dataSourceAlias = value;
        }
    }
    get propertyEditorDataSourceAlias() {
        return this.#propertyContext.getEditorDataSourceAlias();
    }
    /**
     * Config. Configuration to pass to the Property Editor UI. This is also the configuration data stored on the Data Type.
     * @public
     * @type {string}
     * @default
     */
    set config(value) {
        this.#propertyContext.setConfig(value);
    }
    get config() {
        return this.#propertyContext.getConfig();
    }
    /**
     * Validation: Validation settings for the property.
     */
    set validation(validation) {
        this.#propertyContext.setValidation(validation);
    }
    get validation() {
        return this.#propertyContext.getValidation();
    }
    /**
     * DataPath, declare the path to the value of the data that this property represents.
     * @public
     * @type {string}
     * @default
     */
    set dataPath(dataPath) {
        this.#propertyContext.setDataPath(dataPath);
        new UmbObserveValidationStateController(this, dataPath, (invalid) => {
            this._invalid = invalid;
        });
    }
    get dataPath() {
        return this.#propertyContext.getDataPath();
    }
    set readonly(value) {
        this._readonly = value;
        const unique = 'UMB_ELEMENT';
        if (this._readonly) {
            this.#propertyContext.readOnlyState.addState({
                unique,
            });
        }
        else {
            this.#propertyContext.readOnlyState.removeState(unique);
        }
    }
    get readonly() {
        return this._readonly;
    }
    #propertyContext;
    #pathAddendum;
    #controlValidator;
    #validationMessageBinder;
    #valueObserver;
    #configObserver;
    #validationMessageObserver;
    #extensionsController;
    constructor() {
        super();
        /**
         * Sets the property to readonly, meaning value cannot be changed but still able to read and select its content.
         * @type {boolean}
         * @default false
         */
        this._readonly = false;
        this._orientation = 'horizontal';
        this._supportsReadOnly = false;
        this._isReadOnly = false;
        this.#propertyContext = new UmbPropertyContext(this);
        this.#pathAddendum = new UmbRoutePathAddendumContext(this);
        this._onPropertyEditorChange = (e) => {
            const target = e.composedPath()[0];
            if (this._element !== target) {
                console.error("Property Editor received a Change Event who's target is not the Property Editor Element. Do not make bubble and composed change events.");
                return;
            }
            //this.value = target.value; // Sets value in context.
            this.#propertyContext.setValue(target.value);
            e.stopPropagation();
        };
        this.observe(this.#propertyContext.alias, (alias) => {
            this._alias = alias;
            this.#pathAddendum.setAddendum(alias);
        }, null);
        this.observe(this.#propertyContext.label, (label) => {
            this._label = label;
            if (this._element) {
                this._element.name = label;
            }
        }, null);
        this.observe(this.#propertyContext.description, (description) => {
            this._description = description;
        }, null);
        this.observe(this.#propertyContext.variantDifference, (variantDifference) => {
            this._variantDifferenceTerm = variantDifference;
        }, null);
        this.observe(this.#propertyContext.appearance, (appearance) => {
            this._orientation = appearance?.labelOnTop ? 'vertical' : 'horizontal';
        }, null);
        this.observe(this.#propertyContext.validationMandatory, (mandatory) => {
            this._mandatory = mandatory;
            if (this._element) {
                this._element.mandatory = mandatory;
            }
        }, null);
        this.observe(this.#propertyContext.isReadOnly, (value) => {
            this._isReadOnly = value;
            if (this._element) {
                this._element.readonly = value;
                this._element.toggleAttribute('readonly', value);
            }
        }, null);
    }
    _observePropertyEditorUI() {
        if (this._propertyEditorUiAlias) {
            this.observe(umbExtensionsRegistry.byTypeAndAlias('propertyEditorUi', this._propertyEditorUiAlias), (manifest) => {
                if (!manifest && this._propertyEditorUiAlias !== UMB_MISSING_PROPERTY_EDITOR_UI_UI_ALIAS) {
                    this._propertyEditorUiAlias = UMB_MISSING_PROPERTY_EDITOR_UI_UI_ALIAS;
                    this._observePropertyEditorUI();
                    return;
                }
                this._gotEditorUI(manifest);
            }, '_observePropertyEditorUI');
        }
    }
    async _gotEditorUI(manifest) {
        if (this._element && this._element.manifest === manifest) {
            // If we already have an element and the manifest haven't changed, we don't need to do anything.
            return;
        }
        this.#extensionsController?.destroy();
        this.#propertyContext.setEditor(undefined);
        this.#propertyContext.setEditorManifest(manifest ?? undefined);
        if (!manifest) {
            return;
        }
        const el = await createExtensionElement(manifest);
        this._supportsReadOnly = manifest.meta.supportsReadOnly || false;
        if (el) {
            const oldElement = this._element;
            // cleanup:
            this.#valueObserver?.destroy();
            this.#configObserver?.destroy();
            this.#validationMessageObserver?.destroy();
            this.#controlValidator?.destroy();
            oldElement?.removeEventListener('change', this._onPropertyEditorChange);
            /** @deprecated The `UmbPropertyValueChangeEvent` has been deprecated, and will be removed in Umbraco 18. [LK] */
            oldElement?.removeEventListener('property-value-change', this._onPropertyEditorChange);
            oldElement?.destroy?.();
            this._element = el;
            this.#propertyContext.setEditor(this._element);
            if (this._element) {
                this._element.addEventListener('change', this._onPropertyEditorChange);
                /** @deprecated The `UmbPropertyValueChangeEvent` has been deprecated, and will be removed in Umbraco 18. [LK] */
                this._element.addEventListener('property-value-change', this._onPropertyEditorChange);
                // No need to observe mandatory or label, as we already do so and set it on the _element if present: [NL]
                this._element.manifest = manifest;
                this._element.mandatory = this._mandatory;
                this._element.name = this._label;
                this._element.dataSourceAlias = this.#propertyContext.getEditorDataSourceAlias();
                // No need for a controller alias, as the clean is handled via the observer prop:
                this.#valueObserver = this.observe(this.#propertyContext.value, (value) => {
                    // Set the value on the element:
                    this._element.value = value;
                    if (this.#validationMessageBinder) {
                        this.#validationMessageBinder.value = value;
                    }
                }, null);
                this.#configObserver = this.observe(this.#propertyContext.config, (config) => {
                    if (config) {
                        this._element.config = config;
                    }
                }, null);
                this.#validationMessageObserver = this.observe(this.#propertyContext.validationMandatoryMessage, (mandatoryMessage) => {
                    if (mandatoryMessage) {
                        this._element.mandatoryMessage = mandatoryMessage ?? undefined;
                    }
                }, null);
                if ('checkValidity' in this._element) {
                    const dataPath = this.dataPath;
                    this.#controlValidator = new UmbFormControlValidator(this, this._element, dataPath);
                    // We trust blindly that the dataPath will be present at this stage and not arrive later than this moment. [NL]
                    if (dataPath) {
                        this.#validationMessageBinder = new UmbBindServerValidationToFormControl(this, this._element, dataPath);
                        this.#validationMessageBinder.value = this.#propertyContext.getValue();
                    }
                }
                this._element.readonly = this._isReadOnly;
                this._element.toggleAttribute('readonly', this._isReadOnly);
                this.#createController(manifest);
            }
            this.requestUpdate('element', oldElement);
        }
    }
    #createController(propertyEditorUiManifest) {
        if (this.#extensionsController) {
            this.#extensionsController.destroy();
        }
        this.#extensionsController = new UmbExtensionsApiInitializer(this, umbExtensionsRegistry, 'propertyContext', [], (manifest) => manifest.forPropertyEditorUis.includes(propertyEditorUiManifest.alias));
    }
    render() {
        return html `
			<umb-property-layout
				id="layout"
				.alias=${this._alias ?? ''}
				.label=${this._label ?? ''}
				.description=${this._description ?? ''}
				.orientation=${this._orientation ?? 'horizontal'}
				?mandatory=${this._mandatory}
				?invalid=${this._invalid}>
				${this.#renderPropertyActionMenu()}
				${this._variantDifferenceTerm
            ? html `<div id="variant-info" slot="description">
							<uui-tag look="secondary">${this.localize.term(this._variantDifferenceTerm)}</uui-tag>
						</div> `
            : ''}
				${this.#renderPropertyEditor()}
			</umb-property-layout>
		`;
    }
    #renderPropertyActionMenu() {
        if (!this._propertyEditorUiAlias)
            return nothing;
        return html `
			<umb-property-action-menu
				slot="action-menu"
				id="action-menu"
				.propertyEditorUiAlias=${this._propertyEditorUiAlias}>
			</umb-property-action-menu>
		`;
    }
    #renderPropertyEditor() {
        return html `
			<div id="editor" slot="editor">
				${this._isReadOnly && this._supportsReadOnly === false ? html `<div id="overlay"></div>` : nothing}
				${this._element}
			</div>
		`;
    }
    static { this.styles = [
        UmbTextStyles,
        css `
			:host {
				display: block;
			}

			p {
				color: var(--uui-color-text-alt);
			}

			#action-menu {
				opacity: 0;
				transition: opacity 90ms;
			}

			#layout:focus-within #action-menu,
			#layout:hover #action-menu,
			#action-menu[open] {
				opacity: 1;
			}

			#variant-info {
				opacity: 0;
				transition: opacity 90ms;
				margin-top: var(--uui-size-space-2);
				margin-left: calc(var(--uui-size-space-1) * -1);
			}

			#layout:focus-within #variant-info,
			#layout:hover #variant-info {
				opacity: 1;
			}

			#editor {
				position: relative;
			}

			#overlay {
				position: absolute;
				top: 0;
				left: 0;
				right: 0;
				bottom: 0;
				background-color: white;
				opacity: 0.5;
				z-index: 1000;
			}
		`,
    ]; }
};
__decorate([
    property({ type: String })
], UmbPropertyElement.prototype, "label", null);
__decorate([
    property({ type: String })
], UmbPropertyElement.prototype, "description", null);
__decorate([
    property({ type: Object, attribute: false })
], UmbPropertyElement.prototype, "appearance", null);
__decorate([
    property({ type: String })
], UmbPropertyElement.prototype, "alias", null);
__decorate([
    property({ type: String, attribute: 'property-editor-ui-alias' })
], UmbPropertyElement.prototype, "propertyEditorUiAlias", null);
__decorate([
    property({ type: String, attribute: 'property-editor-data-source-alias' })
], UmbPropertyElement.prototype, "propertyEditorDataSourceAlias", null);
__decorate([
    property({ type: Array, attribute: false })
], UmbPropertyElement.prototype, "config", null);
__decorate([
    property({ type: Object, attribute: false })
], UmbPropertyElement.prototype, "validation", null);
__decorate([
    property({ type: String, attribute: 'data-path' })
], UmbPropertyElement.prototype, "dataPath", null);
__decorate([
    property({ type: Boolean, reflect: true })
], UmbPropertyElement.prototype, "readonly", null);
__decorate([
    state()
], UmbPropertyElement.prototype, "_variantDifferenceTerm", void 0);
__decorate([
    state()
], UmbPropertyElement.prototype, "_element", void 0);
__decorate([
    state()
], UmbPropertyElement.prototype, "_invalid", void 0);
__decorate([
    state()
], UmbPropertyElement.prototype, "_alias", void 0);
__decorate([
    state()
], UmbPropertyElement.prototype, "_label", void 0);
__decorate([
    state()
], UmbPropertyElement.prototype, "_description", void 0);
__decorate([
    state()
], UmbPropertyElement.prototype, "_orientation", void 0);
__decorate([
    state()
], UmbPropertyElement.prototype, "_mandatory", void 0);
__decorate([
    state()
], UmbPropertyElement.prototype, "_supportsReadOnly", void 0);
__decorate([
    state()
], UmbPropertyElement.prototype, "_isReadOnly", void 0);
UmbPropertyElement = __decorate([
    customElement('umb-property')
], UmbPropertyElement);
export { UmbPropertyElement };
