import { UmbDataPathPropertyTypeQuery } from '../utils/index.js';
import { UmbPropertyTypeWorkspaceEditorElement } from './property-type-workspace-editor.element.js';
import { UmbSubmittableWorkspaceContextBase, UmbInvariantWorkspacePropertyDatasetContext, UmbWorkspaceIsNewRedirectController, UmbWorkspaceIsNewRedirectControllerAlias, umbObjectToPropertyValueArray, } from '../../../core/workspace/index.js';
import { UmbObjectState } from '../../../../libs/observable-api/index.js';
import { UMB_CONTENT_TYPE_WORKSPACE_CONTEXT } from '../../content-type/index.js';
import { UmbId } from '../../../core/id/index.js';
import { firstValueFrom } from '../../../../external/rxjs/index.js';
import { UmbValidationContext } from '../../../core/validation/index.js';
export class UmbPropertyTypeWorkspaceContext extends UmbSubmittableWorkspaceContextBase {
    #init;
    #contentTypeContext;
    #entityType;
    // #persistedData
    // #currentData
    #data;
    async getValues() {
        return umbObjectToPropertyValueArray(await firstValueFrom(this.data));
    }
    constructor(host, args) {
        super(host, args.manifest.alias);
        // Just for context token safety:
        this.IS_PROPERTY_TYPE_WORKSPACE_CONTEXT = true;
        // #persistedData
        // #currentData
        this.#data = new UmbObjectState(undefined);
        this.data = this.#data.asObservable();
        this.name = this.#data.asObservablePart((data) => data?.name);
        this.unique = this.#data.asObservablePart((data) => data?.unique);
        this.values = this.#data.asObservablePart((data) => {
            return umbObjectToPropertyValueArray(data);
        });
        const manifest = args.manifest;
        this.#entityType = manifest.meta?.entityType;
        this.validationContext = new UmbValidationContext(this);
        this.addValidationContext(this.validationContext);
        this.observe(this.unique, (unique) => {
            if (unique) {
                this.validationContext.setDataPath(UmbDataPathPropertyTypeQuery({ unique }));
            }
        }, null);
        this.observe(this.name, (name) => {
            this.view.setTitle(name);
        }, null);
        this.#init = this.consumeContext(UMB_CONTENT_TYPE_WORKSPACE_CONTEXT, (context) => {
            this.#contentTypeContext = context;
        })
            .skipHost()
            .asPromise({ preventTimeout: true })
            .catch(() => {
            // If the context is not available, we can assume that the context is not available.
            this.#contentTypeContext = undefined;
        });
        this.routes.setRoutes([
            {
                // Would it make more sense to have groupKey before elementTypeKey?
                path: 'create/:containerUnique',
                component: UmbPropertyTypeWorkspaceEditorElement,
                setup: async (component, info) => {
                    const containerUnique = info.match.params.containerUnique === 'null' ? null : info.match.params.containerUnique;
                    await this.create(containerUnique);
                    new UmbWorkspaceIsNewRedirectController(this, this, this.getHostElement().shadowRoot.querySelector('umb-router-slot'));
                },
            },
            {
                path: 'edit/:unique',
                component: UmbPropertyTypeWorkspaceEditorElement,
                setup: (component, info) => {
                    const unique = info.match.params.unique;
                    this.load(unique);
                },
            },
        ]);
    }
    resetState() {
        super.resetState();
        this.#data.setValue(undefined);
        this.removeUmbControllerByAlias(UmbWorkspaceIsNewRedirectControllerAlias);
        this.removeUmbControllerByAlias('observePropertyTypeData');
    }
    createPropertyDatasetContext(host) {
        return new UmbInvariantWorkspacePropertyDatasetContext(host, this);
    }
    async load(unique) {
        this.resetState();
        await this.#init;
        this.observe(await this.#contentTypeContext?.structure.propertyStructureById(unique), (property) => {
            if (property) {
                this.#data.setValue(property);
                //this.#persistedData.setValue(property);
                //this.#currentData.setValue(property);
                this.setIsNew(false);
            }
            else {
                // Fallback to undefined:
                this.#data.setValue(undefined);
            }
        }, 'observePropertyTypeData');
    }
    async create(containerId) {
        this.resetState();
        const unique = UmbId.new();
        let data = {
            unique: unique,
            container: containerId ? { id: containerId } : null,
            alias: '',
            name: '',
            description: '',
            variesByCulture: false,
            variesBySegment: false,
            validation: {
                mandatory: false,
                mandatoryMessage: null,
                regEx: null,
                regExMessage: null,
            },
            appearance: {
                labelOnTop: false,
            },
            sortOrder: 0,
        };
        // If we have a modal context, we blend in the modal preset data: [NL]
        if (this.modalContext) {
            data = { ...data, ...this.modalContext.data.preset };
        }
        this.#data.setValue(data);
        //this.#persistedData.setValue(property);
        //this.#currentData.setValue(property);
        this.setIsNew(true);
    }
    getData() {
        return this.#data.getValue();
    }
    updateData(partialData) {
        this.#data?.update(partialData);
    }
    getUnique() {
        return this.getData().unique;
    }
    getEntityType() {
        return this.#entityType;
    }
    getName() {
        return this.#data.getValue()?.name;
    }
    setName(name) {
        this.updateData({ name: name });
    }
    /**
     * @function propertyValueByAlias
     * @param {string} propertyAlias
     * @returns {Promise<Observable<ReturnType | undefined> | undefined>}
     * @description Get an Observable for the value of this property.
     */
    async propertyValueByAlias(propertyAlias) {
        return this.#data.asObservablePart((data) => data?.[propertyAlias]);
    }
    getPropertyValue(propertyAlias) {
        return this.#data.getValue()?.[propertyAlias];
    }
    /**
     * @function setPropertyValue
     * @param {string} propertyAlias
     * @param alias
     * @param {PromiseLike<unknown>} value - value can be a promise resolving into the actual value or the raw value it self.
     * @returns {Promise<void>}
     * @description Set the value of this property.
     */
    async setPropertyValue(alias, value) {
        const currentData = this.#data.value;
        if (currentData) {
            this.#data.update({ ...currentData, [alias]: value });
        }
    }
    async submit() {
        if (!this.modalContext) {
            throw new Error('Needs to be in a modal to submit.');
        }
        const contentTypeUnique = this.modalContext.data.contentTypeUnique;
        const data = this.#data.getValue();
        if (!data) {
            throw new Error('No data to submit.');
        }
        await this.#init;
        if (this.#contentTypeContext) {
            this.validationContext.report();
            await this.#contentTypeContext.structure.insertProperty(contentTypeUnique, data);
            this.setIsNew(false);
        }
        else {
            throw new Error('Failed to find content type context.');
        }
    }
    destroy() {
        this.#data.destroy();
        super.destroy();
    }
}
export { UmbPropertyTypeWorkspaceContext as api };
