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 { UMB_CONTENT_TYPE_WORKSPACE_CONTEXT } from '../../content-type-workspace.context-token.js';
import { UmbContentTypePropertyStructureHelper } from '../../../structure/index.js';
import { UMB_CONTENT_TYPE_DESIGN_EDITOR_CONTEXT } from './content-type-design-editor.context-token.js';
import { css, customElement, html, ifDefined, property, repeat, state, when, } from '../../../../../../external/lit/index.js';
import { UmbLitElement } from '../../../../../core/lit-element/index.js';
import { UmbTextStyles } from '../../../../../core/style/index.js';
import { UmbSorterController } from '../../../../../core/sorter/index.js';
import { UmbModalRouteRegistrationController } from '../../../../../core/router/index.js';
import { UMB_CREATE_PROPERTY_TYPE_WORKSPACE_PATH_PATTERN, UMB_PROPERTY_TYPE_WORKSPACE_MODAL, } from '../../../../property-type/index.js';
import './content-type-design-editor-property.element.js';
const SORTER_CONFIG = {
    getUniqueOfElement: (element) => {
        return element.getAttribute('data-umb-property-id');
    },
    getUniqueOfModel: (modelEntry) => {
        return modelEntry.unique;
    },
    identifier: 'content-type-property-sorter',
    itemSelector: 'umb-content-type-design-editor-property',
    disabledItemSelector: '[_inherited]',
    //TODO: Set the property list (sorter wrapper) to inherited, if its inherited
    // This is because we don't want to move local properties into an inherited group container.
    // Or maybe we do, but we still need to check if the group exists locally, if not, then it needs to be created before we move a property into it.
    // TODO: Fix bug where a local property turn into an inherited when moved to a new group container.
    containerSelector: '#property-list',
};
let UmbContentTypeDesignEditorPropertiesElement = class UmbContentTypeDesignEditorPropertiesElement extends UmbLitElement {
    #sorter;
    get containerId() {
        return this._containerId;
    }
    set containerId(value) {
        if (value === this._containerId)
            return;
        this._containerId = value;
        this.#createPropertyTypeWorkspaceRoutes();
        this.#propertyStructureHelper.setContainerId(value);
        this.#addPropertyModal?.setUniquePathValue('container-id', value === null ? 'root' : value);
        this.#editPropertyModal?.setUniquePathValue('container-id', value === null ? 'root' : value);
    }
    #addPropertyModal;
    #editPropertyModal;
    #propertyStructureHelper;
    #initResolver;
    #initReject;
    #init;
    constructor() {
        super();
        this.#sorter = new UmbSorterController(this, {
            ...SORTER_CONFIG,
            onChange: ({ model }) => {
                this._properties = model;
            },
            onContainerChange: async ({ item }) => {
                if (this._containerId === undefined) {
                    throw new Error('ContainerId is not set');
                }
                if (this._ownerContentTypeUnique === undefined) {
                    throw new Error('OwnerContentTypeUnique is not set');
                }
                let containerId = this._containerId;
                // ensure container is local:
                if (this._containerId !== null) {
                    const container = await this.#propertyStructureHelper
                        .getStructureManager()
                        ?.ensureContainerOf(this._containerId, this._ownerContentTypeUnique);
                    containerId = container?.id || this._containerId;
                }
                this.#propertyStructureHelper.partialUpdateProperty(item.unique, {
                    container: containerId ? { id: containerId } : null,
                });
            },
            onEnd: ({ item }) => {
                if (this._containerId === undefined) {
                    throw new Error('ContainerId is not set.');
                }
                /**
                 * Explanation: If the item is the first in list, we compare it to the item behind it to set a sortOrder.
                 * If it's not the first in list, we will compare to the item in before it, and check the following item to see if it caused overlapping sortOrder, then update
                 * the overlap if true, which may cause another overlap, so we loop through them till no more overlaps...
                 */
                const model = this._properties;
                const newIndex = model.findIndex((entry) => entry.unique === item.unique);
                // Doesn't exist in model
                if (newIndex === -1)
                    return;
                // As origin we set prev sort order to -1, so if no other then our item will become 0
                let prevSortOrder = -1;
                // Not first in list
                if (newIndex > 0 && model.length > 0) {
                    prevSortOrder = model[newIndex - 1].sortOrder;
                }
                // increase the prevSortOrder and use it for the moved item,
                this.#propertyStructureHelper.partialUpdateProperty(item.unique, {
                    sortOrder: ++prevSortOrder,
                });
                // Adjust everyone right after, meaning until there is a gap between the sortOrders:
                let i = newIndex + 1;
                let entry;
                // As long as there is an item with the index & the sortOrder is less or equal to the prevSortOrder, we will update the sortOrder:
                while ((entry = model[i]) !== undefined && entry.sortOrder <= prevSortOrder) {
                    // Increase the prevSortOrder and use it for the item:
                    this.#propertyStructureHelper.partialUpdateProperty(entry.unique, {
                        sortOrder: ++prevSortOrder,
                    });
                    i++;
                }
            },
            onRequestDrop: async ({ unique }) => {
                const context = await this.getContext(UMB_CONTENT_TYPE_WORKSPACE_CONTEXT);
                if (!context) {
                    throw new Error('Could not get Workspace Context');
                }
                return context.structure.getOwnerPropertyById(unique);
            },
            requestExternalRemove: async ({ item }) => {
                const context = await this.getContext(UMB_CONTENT_TYPE_WORKSPACE_CONTEXT);
                if (!context) {
                    throw new Error('Could not get Workspace Context');
                }
                return await context.structure.removeProperty(null, item.unique).then(() => true, () => false);
            },
            requestExternalInsert: async ({ item }) => {
                const context = await this.getContext(UMB_CONTENT_TYPE_WORKSPACE_CONTEXT);
                if (!context) {
                    throw new Error('Could not get Workspace Context');
                }
                const parent = this._containerId ? { id: this._containerId } : null;
                const updatedItem = { ...item, parent };
                return await context.structure.insertProperty(null, updatedItem).then(() => true, () => false);
            },
        });
        this.#propertyStructureHelper = new UmbContentTypePropertyStructureHelper(this);
        this.#init = new Promise((resolve, reject) => {
            this.#initResolver = resolve;
            this.#initReject = reject;
        });
        this._properties = [];
        //this.#sorter.disable();
        this.consumeContext(UMB_CONTENT_TYPE_DESIGN_EDITOR_CONTEXT, (context) => {
            this.observe(context?.isSorting, (isSorting) => {
                this._sortModeActive = isSorting;
            }, '_observeIsSorting');
        });
        this.consumeContext(UMB_CONTENT_TYPE_WORKSPACE_CONTEXT, async (workspaceContext) => {
            if (workspaceContext) {
                this.#propertyStructureHelper.setStructureManager(workspaceContext.structure);
            }
            this._ownerContentTypeUnique = workspaceContext?.structure.getOwnerContentTypeUnique();
            this.#createPropertyTypeWorkspaceRoutes();
            const varyByCulturePromise = this.observe(workspaceContext?.variesByCulture, (variesByCulture) => {
                this._ownerContentTypeVariesByCulture = variesByCulture;
            }, 'observeOwnerVariesByCulture')?.asPromise();
            const varyBySegmentPromise = this.observe(workspaceContext?.variesBySegment, (variesBySegment) => {
                this._ownerContentTypeVariesBySegment = variesBySegment;
            }, 'observeOwnerVariesBySegment')?.asPromise();
            if (varyByCulturePromise && varyBySegmentPromise && this.#initResolver) {
                Promise.all([varyByCulturePromise, varyBySegmentPromise])
                    .then(() => {
                    this.#initResolver?.();
                    this.#initResolver = undefined;
                    this.#initReject = undefined;
                })
                    .catch(() => { });
            }
        });
        this.observe(this.#propertyStructureHelper.propertyStructure, (propertyStructure) => {
            this._properties = propertyStructure;
            this.#sorter.setModel(this._properties);
        });
    }
    disconnectedCallback() {
        super.disconnectedCallback();
        this.#initReject?.(new Error('Component disconnected'));
    }
    async #createPropertyTypeWorkspaceRoutes() {
        await this.#init;
        if (!this._ownerContentTypeUnique || this._containerId === undefined)
            return;
        // Note: Route for adding a new property
        this.#addPropertyModal?.destroy();
        this.#addPropertyModal = new UmbModalRouteRegistrationController(this, UMB_PROPERTY_TYPE_WORKSPACE_MODAL, 'addPropertyModal')
            .addUniquePaths(['container-id'])
            .addAdditionalPath('add-property/:sortOrder')
            .onSetup(async (params) => {
            // TODO: Make a onInit promise, that can be awaited here.
            if (!this._ownerContentTypeUnique || this._containerId === undefined)
                return false;
            const preset = {};
            if (params.sortOrder !== undefined) {
                let sortOrderInt = parseInt(params.sortOrder);
                if (sortOrderInt === -1) {
                    // Find the highest sortOrder and add 1 to it:
                    sortOrderInt = Math.max(...this._properties.map((x) => x.sortOrder), -1) + 1;
                }
                preset.sortOrder = sortOrderInt;
            }
            if (this._ownerContentTypeVariesByCulture) {
                preset.variesByCulture = true;
            }
            if (this._ownerContentTypeVariesBySegment) {
                preset.variesBySegment = true;
            }
            return { data: { contentTypeUnique: this._ownerContentTypeUnique, preset: preset } };
        })
            .observeRouteBuilder((routeBuilder) => {
            this._newPropertyPath =
                routeBuilder({ sortOrder: '-1' }) +
                    UMB_CREATE_PROPERTY_TYPE_WORKSPACE_PATH_PATTERN.generateLocal({
                        containerUnique: this._containerId,
                    });
        });
        if (this._containerId !== undefined) {
            this.#addPropertyModal?.setUniquePathValue('container-id', this._containerId === null ? 'root' : this._containerId);
        }
        this.#editPropertyModal?.destroy();
        this.#editPropertyModal = new UmbModalRouteRegistrationController(this, UMB_PROPERTY_TYPE_WORKSPACE_MODAL, 'editPropertyModal')
            .addUniquePaths(['container-id'])
            .addAdditionalPath('edit-property')
            .onSetup(async () => {
            if (!this._ownerContentTypeUnique || this._containerId === undefined)
                return false;
            return { data: { contentTypeUnique: this._ownerContentTypeUnique, preset: undefined } };
        })
            .observeRouteBuilder((routeBuilder) => {
            this._editPropertyTypePath = routeBuilder(null);
        });
        if (this._containerId !== undefined) {
            this.#editPropertyModal?.setUniquePathValue('container-id', this._containerId === null ? 'root' : this._containerId);
        }
    }
    render() {
        return this._ownerContentTypeUnique
            ? html `
					<div id="property-list" ?sort-mode-active=${this._sortModeActive}>
						${repeat(this._properties, (property) => property.unique, (property) => {
                return html `
									<umb-content-type-design-editor-property
										data-umb-property-id=${property.unique}
										data-mark="property-type:${property.name}"
										.editContentTypePath=${this.editContentTypePath}
										.editPropertyTypePath=${this._editPropertyTypePath}
										?sort-mode-active=${this._sortModeActive}
										.propertyStructureHelper=${this.#propertyStructureHelper}
										.property=${property}
										.ownerVariesByCulture=${this._ownerContentTypeVariesByCulture}
										.ownerVariesBySegment=${this._ownerContentTypeVariesBySegment}>
									</umb-content-type-design-editor-property>
								`;
            })}
					</div>

					${when(!this._sortModeActive, () => html `
							<uui-button
								id="btn-add"
								href=${ifDefined(this._newPropertyPath)}
								label=${this.localize.term('contentTypeEditor_addProperty')}
								look="placeholder"></uui-button>
						`)}
				`
            : '';
    }
    static { this.styles = [
        UmbTextStyles,
        css `
			:host {
				display: block;
			}

			#property-list {
				/* enables dropping things into this despite it begin empty. */
				margin-top: -20px;
				padding-top: 20px;
			}

			#btn-add {
				width: 100%;
				--uui-button-height: var(--uui-size-14);
			}

			#property-list[sort-mode-active]:not(:has(umb-content-type-design-editor-property)) {
				/* Some height so that the sorter can target the area if the group is empty*/
				min-height: var(--uui-size-layout-1);
			}
		`,
    ]; }
};
__decorate([
    property({ type: String, attribute: 'container-id', reflect: false })
], UmbContentTypeDesignEditorPropertiesElement.prototype, "containerId", null);
__decorate([
    property({ attribute: false })
], UmbContentTypeDesignEditorPropertiesElement.prototype, "editContentTypePath", void 0);
__decorate([
    state()
], UmbContentTypeDesignEditorPropertiesElement.prototype, "_properties", void 0);
__decorate([
    state()
], UmbContentTypeDesignEditorPropertiesElement.prototype, "_ownerContentTypeUnique", void 0);
__decorate([
    state()
], UmbContentTypeDesignEditorPropertiesElement.prototype, "_ownerContentTypeVariesByCulture", void 0);
__decorate([
    state()
], UmbContentTypeDesignEditorPropertiesElement.prototype, "_ownerContentTypeVariesBySegment", void 0);
__decorate([
    state()
], UmbContentTypeDesignEditorPropertiesElement.prototype, "_newPropertyPath", void 0);
__decorate([
    state()
], UmbContentTypeDesignEditorPropertiesElement.prototype, "_editPropertyTypePath", void 0);
__decorate([
    state()
], UmbContentTypeDesignEditorPropertiesElement.prototype, "_sortModeActive", void 0);
UmbContentTypeDesignEditorPropertiesElement = __decorate([
    customElement('umb-content-type-design-editor-properties')
], UmbContentTypeDesignEditorPropertiesElement);
export { UmbContentTypeDesignEditorPropertiesElement };
export default UmbContentTypeDesignEditorPropertiesElement;
