import { UMB_BLOCK_RTE_WORKSPACE_MODAL } from '../workspace/block-rte-workspace.modal-token.js';
import { UMB_BLOCK_RTE_MANAGER_CONTEXT } from './block-rte-manager.context-token.js';
import { UmbBlockEntriesContext, UMB_BLOCK_CATALOGUE_MODAL } from '../../block/index.js';
import { UmbBooleanState } from '../../../../libs/observable-api/index.js';
import { UmbClipboardPastePropertyValueTranslatorValueResolver, UMB_CLIPBOARD_PROPERTY_CONTEXT, } from '../../../clipboard/index.js';
import { UmbModalRouteRegistrationController } from '../../../core/router/index.js';
import { UMB_PROPERTY_CONTEXT } from '../../../core/property/index.js';
/**
 * Copied from the 'rte' package to avoid a circular dependency.
 * @internal
 */
const UMB_BLOCK_RTE_PROPERTY_EDITOR_SCHEMA_ALIAS = 'Umbraco.RichText';
/**
 * Copied from the 'tiptap' package to avoid a circular dependency.
 * @internal
 */
const UMB_BLOCK_RTE_PROPERTY_EDITOR_UI_ALIAS = 'Umb.PropertyEditorUi.Tiptap';
export class UmbBlockRteEntriesContext extends UmbBlockEntriesContext {
    constructor(host) {
        super(host, UMB_BLOCK_RTE_MANAGER_CONTEXT);
        //
        // We will just say its always allowed for RTE for now: [NL]
        this.canCreate = new UmbBooleanState(true).asObservable();
        new UmbModalRouteRegistrationController(this, UMB_BLOCK_CATALOGUE_MODAL)
            .addAdditionalPath('_catalogue/:view')
            .onSetup(async (routingInfo) => {
            const blockTypes = this._manager?.getBlockTypes() ?? [];
            /*
            modal size logic:
            If more than 8 block types, medium modal, more than 12 large modal:
            */
            const modalSize = blockTypes.length > 12 ? 'large' : blockTypes.length > 8 ? 'medium' : 'small';
            await this._retrieveManager;
            if (!this._manager)
                return false;
            const clipboardContext = await this.getContext(UMB_CLIPBOARD_PROPERTY_CONTEXT);
            if (!clipboardContext) {
                throw new Error('Clipboard context not found');
            }
            const pasteTranslatorManifests = clipboardContext.getPasteTranslatorManifests(UMB_BLOCK_RTE_PROPERTY_EDITOR_UI_ALIAS);
            // TODO: consider moving some of this logic to the clipboard property context
            const propertyContext = await this.getContext(UMB_PROPERTY_CONTEXT);
            if (!propertyContext) {
                throw new Error('Property context not found');
            }
            const config = propertyContext.getConfig();
            const valueResolver = new UmbClipboardPastePropertyValueTranslatorValueResolver(this);
            return {
                modal: { size: modalSize },
                data: {
                    blocks: blockTypes,
                    blockGroups: [],
                    openClipboard: routingInfo.view === 'clipboard',
                    clipboardFilter: async (clipboardEntryDetail) => {
                        const hasSupportedPasteTranslator = clipboardContext.hasSupportedPasteTranslator(pasteTranslatorManifests, clipboardEntryDetail.values);
                        if (!hasSupportedPasteTranslator) {
                            return false;
                        }
                        const pasteTranslator = await valueResolver.getPasteTranslator(clipboardEntryDetail.values, UMB_BLOCK_RTE_PROPERTY_EDITOR_UI_ALIAS);
                        if (pasteTranslator.isCompatibleValue) {
                            const value = await valueResolver.resolve(clipboardEntryDetail.values, UMB_BLOCK_RTE_PROPERTY_EDITOR_UI_ALIAS);
                            return pasteTranslator.isCompatibleValue(value, config);
                        }
                        return true;
                    },
                    originData: {},
                    createBlockInWorkspace: true,
                },
            };
        })
            .onSubmit(async (value, data) => {
            if (value?.create && data) {
                const created = await this.create(value.create.contentElementTypeKey, {}, data.originData);
                if (created) {
                    await this.insert(created.layout, created.content, created.settings, data.originData);
                }
                else {
                    throw new Error('Failed to create block');
                }
            }
            else if (value?.clipboard && value.clipboard.selection?.length && data) {
                const clipboardContext = await this.getContext(UMB_CLIPBOARD_PROPERTY_CONTEXT);
                if (!clipboardContext) {
                    throw new Error('Clipboard context not found');
                }
                const propertyValues = await clipboardContext.readMultiple(value.clipboard.selection, UMB_BLOCK_RTE_PROPERTY_EDITOR_UI_ALIAS);
                await this.#insertFromRtePropertyValues(propertyValues, data.originData);
            }
        })
            .observeRouteBuilder((routeBuilder) => {
            this._catalogueRouteBuilderState.setValue(routeBuilder);
        });
        new UmbModalRouteRegistrationController(this, UMB_BLOCK_RTE_WORKSPACE_MODAL)
            .addAdditionalPath('block')
            .onSetup(() => {
            return { data: { entityType: 'block', preset: {}, baseDataPath: this._dataPath }, modal: { size: 'medium' } };
        })
            .observeRouteBuilder((routeBuilder) => {
            const newPath = routeBuilder({});
            this._workspacePath.setValue(newPath);
        });
    }
    _gotBlockManager() {
        if (!this._manager)
            return;
        this.observe(this._manager.layouts, (layouts) => {
            this._layoutEntries.setValue(layouts);
        }, 'observeParentLayouts');
        this.observe(this.layoutEntries, (layouts) => {
            this._manager?.setLayouts(layouts);
        }, 'observeThisLayouts');
    }
    getPathForCreateBlock() {
        return this._catalogueRouteBuilderState.getValue()?.({ view: 'create' });
    }
    getPathForClipboard() {
        return this._catalogueRouteBuilderState.getValue()?.({ view: 'clipboard' });
    }
    async setLayouts(layouts) {
        await this._retrieveManager;
        this._manager?.setLayouts(layouts);
    }
    async create(contentElementTypeKey, partialLayoutEntry, originData) {
        await this._retrieveManager;
        return await this._manager?.createWithPresets(contentElementTypeKey, partialLayoutEntry, originData);
    }
    async insert(layoutEntry, content, settings, originData) {
        await this._retrieveManager;
        return this._manager?.insert(layoutEntry, content, settings, originData) ?? false;
    }
    /**
     * Delete a block by requesting its removal through the pending deletion mechanism.
     * This enables undo support by removing the HTML element first via Tiptap,
     * which triggers _filterUnusedBlocks to store block data before removal.
     * @param {string} contentKey - The content key of the block to delete.
     */
    async delete(contentKey) {
        await this._retrieveManager;
        this._manager?.requestPendingDeletion(contentKey);
    }
    async #insertFromRtePropertyValues(values, originData) {
        for (const value of values) {
            originData = await this.#insertFromRtePropertyValue(value, originData);
        }
    }
    async #insertFromRtePropertyValue(value, originData) {
        if (!value.blocks) {
            throw new Error('No blocks found in property value');
        }
        const layoutEntries = value.blocks.layout[UMB_BLOCK_RTE_PROPERTY_EDITOR_SCHEMA_ALIAS];
        if (!layoutEntries) {
            throw new Error('No layout entries found');
        }
        await Promise.all(layoutEntries.map(async (layoutEntry) => {
            this._insertBlockFromPropertyValue(layoutEntry, value.blocks, originData);
            // TODO: Missing some way to insert a Block HTML Element into the RTE at the current cursor point. (hopefully the responsibility can be avoided here, but there is some connection missing at this point) [NL]
        }));
        return originData;
    }
    // This method is required by the base class but is not used for RTE blocks.
    // RTE blocks use `#insertFromRtePropertyValue` instead because they expect
    // `UmbPropertyEditorRteValueType` (with markup and blocks) rather than `UmbBlockValueType`.
    _insertFromPropertyValue(_value, _originData) {
        throw new Error('Use #insertFromRtePropertyValue for RTE blocks');
    }
}
