'use strict';
import { ArraySetting, createSettingFromSchema, Setting, StructSetting } from '../../../customizables/revised-ui/settings.js';
import { ServiceRegistry } from '../../../customizables/revised-ui/registry.js';
import { registerRevisedUiComponents } from '../../../customizables/revised-ui/component-collection.js';
import { AmeRevEventButton } from '../../../customizables/revised-ui/components/ame-rev-event-button/ame-rev-event-button.js';
import { UiPack } from '../../../customizables/revised-ui/ui-pack.js';
class RevisedUiDevVm {
    constructor(config) {
        this.adminCssSection = null;
        this.lastUserTweakSuffix = 0;
        this.cachedCodeEditorParams = null;
        console.log('RevisedUiDevVm initialized with config:', config);
        const actorSelector = new AmeActorSelector(AmeActors, true);
        actorSelector.setSelectedActorFromUrl();
        const registry = ServiceRegistry.init()
            .register('actorSelector', actorSelector);
        this.mainUi = new UiPack(config.mainUi, registry, (c) => {
            if (c.t === 'container' && !(c.role === 'group')) {
                c = { ...c, component: 'ame-rev-postbox-section' };
            }
            //Register the admin CSS section container so we can add new tweaks to it later.
            if (c.id === 'twm-section_admin-css' && c.t === 'container') {
                c.registerSelf = (container) => {
                    this.adminCssSection = container;
                };
            }
            return c;
        });
        const storedLastSuffix = this.mainUi.settings
            .getChildByPath('ws_ame_tweak_settings--lastUserTweakSuffix')
            .map(setting => setting.value())
            .getOrElse(() => 0);
        if (typeof storedLastSuffix === 'number') {
            this.lastUserTweakSuffix = storedLastSuffix;
        }
        else {
            console.warn('Expected lastUserTweakSuffix to be a number, but got:', storedLastSuffix);
        }
        this.addUrlBlockDialog = new AddUrlBlockDialog((blockData) => {
            console.log('Adding new URL Block with data:', blockData);
            const blocks = this.getBlocksArraySetting();
            blocks.addItem(blockData);
        });
        this.adminCssEditorDialog = new EditAdminCssDialogV3(this);
        const sectionIds = [];
        this.getDefaultSlotContent(config.mainUi.interfaceStructure).forEach((child) => {
            if (child.t === 'container' && (typeof child.id === 'string')) {
                sectionIds.push(child.id);
            }
        });
        console.log('Section IDs found in main UI:', sectionIds);
    }
    // noinspection JSUnusedGlobalSymbols -- Used for debugging in the console.
    getSettingValue(key) {
        const setting = this.mainUi.settings.getChild(key);
        if (setting.isDefined()) {
            return setting.get().value();
        }
        else {
            console.warn(`Setting with key "${key}" not found.`);
            return null;
        }
    }
    onToggleUrlBlockEditor(_unused, event) {
        console.log('Toggle URL Block Editor event triggered:', event);
        const $container = jQuery(event.target).closest('.ame-rui-block-by-url-container');
        const $panel = $container.find('.ame-rui-block-by-url-edit-panel').first();
        $panel.toggle().removeClass('hidden');
        if (event.originalEvent instanceof CustomEvent) {
            const detail = event.originalEvent.detail;
            if (detail && (detail.eventButton instanceof AmeRevEventButton)) {
                const isOpen = $panel.is(':visible');
                detail.eventButton.customLabel(isOpen ? 'Close' : 'Edit');
                detail.eventButton.customIconClass(isOpen ? 'dashicons dashicons-arrow-up' : 'dashicons dashicons-arrow-right');
            }
        }
    }
    getBlocksArraySetting() {
        return this.mainUi.settings.getChild('ame_revised_ui_test_settings--sampleBlocksByUrl')
            .map((blocks) => {
            if (blocks instanceof ArraySetting) {
                return blocks;
            }
            else {
                throw new Error('Expected sampleBlocksByUrl to be an ArraySetting, but it was not: ' + blocks);
            }
        })
            .getOrThrow('sampleBlocksByUrl setting is not defined');
    }
    onDeleteUrlBlock(_unused, event) {
        console.log('Delete URL Block event triggered', event);
        if (!confirm('Delete this URL block?')) {
            return;
        }
        const blocks = this.getBlocksArraySetting();
        const detail = this.getCustomEventDetail(event);
        if (detail && (detail.data instanceof Setting)) {
            const blockToDelete = detail.data;
            blocks.removeItem(blockToDelete);
            console.log('Deleted URL Block:', blockToDelete);
        }
        else {
            console.warn('Delete URL Block event did not contain a valid Setting in its detail:', detail);
        }
    }
    onAddUrlBlock(_unused, event) {
        console.log('Add URL Block event triggered', event);
        this.addUrlBlockDialog.isOpen(true);
    }
    onAddCssSnippet(_unused, event) {
        console.log('Add CSS Snippet event triggered', event);
        this.adminCssEditorDialog.isOpen(true);
    }
    onEditTweak(_unused, event) {
        const detail = this.getCustomEventDetail(event);
        console.log('Edit Tweak event triggered', event, 'with detail:', detail);
        if (!(detail.data instanceof Setting)) {
            console.warn('Edit Tweak event did not contain a valid Setting in its detail:', detail);
            return;
        }
        this.adminCssEditorDialog.selectedTweak = detail.data;
        this.adminCssEditorDialog.isOpen(true);
    }
    onDeleteTweak(_unused, event) {
        const detail = this.getCustomEventDetail(event);
        console.log('Delete Tweak event triggered', event, 'with detail:', detail);
        //Note: In this case, the event data is expected to be the tweak's ID (a string), not a Setting.
        if (typeof detail.data !== 'string') {
            console.warn('Delete Tweak event did not contain a valid tweak ID in its detail:', detail);
            return;
        }
        if (!this.adminCssSection) {
            throw new Error('Admin CSS section is not available');
        }
        const tweakId = detail.data;
        const tweaks = this.getTweaksStructSetting();
        const tweakToDelete = tweaks.getChild(tweakId);
        if (!tweakToDelete.isDefined()) {
            console.warn(`Tweak with ID "${tweakId}" not found in tweaks setting.`);
            return;
        }
        if (!confirm('Delete this admin CSS snippet?')) {
            return;
        }
        //Find the corresponding control in the admin CSS section and remove it.
        const children = this.adminCssSection.slots['default'];
        for (const [index, child] of children().entries()) {
            if (child.t === 'control' && child.objectId === tweakId) {
                children.splice(index, 1);
                console.log(`Removed control for tweak ID "${tweakId}" from admin CSS section.`);
                break;
            }
        }
        //Remove the tweak settings.
        tweaks.removeSetting(tweakId);
    }
    getCustomEventDetail(event) {
        if (event.originalEvent instanceof CustomEvent) {
            return event.originalEvent.detail;
        }
        return null;
    }
    addAdminCssTweak(settingToCopy) {
        if (!this.adminCssSection) {
            throw new Error('Admin CSS section is not available');
        }
        this.lastUserTweakSuffix++;
        const value = settingToCopy.value();
        if (!value) {
            throw new Error('Invalid setting value'); //This should never happen.
        }
        console.log('Adding new admin CSS snippet with value:', value);
        const label = value['label'] || 'New Snippet';
        let slug = RevisedUiDevVm.slugify(label);
        if (slug !== '') {
            slug = '-' + slug;
        }
        const newTweakId = 'utw-' + this.lastUserTweakSuffix + slug;
        const settingPath = RevisedUiDevVm.tweaksSettingId + '.' + newTweakId;
        const tweaks = this.getTweaksStructSetting();
        tweaks.addSetting(newTweakId, createSettingFromSchema(settingToCopy.getSchema(), value));
        //Create the control: an actor feature checkbox with a nested code editor.
        const defaultEditorParams = this.getDefaultCodeEditorParams();
        const newControl = {
            t: 'control',
            label: { t: 'binding', bind: settingPath + '.label' },
            component: 'ame-rev-actor-feature',
            bindings: { value: settingPath + '.enabledForActor' },
            hasTweakActions: true,
            objectId: newTweakId,
            slots: {
                default: [
                    {
                        ...defaultEditorParams,
                        t: 'control',
                        label: '',
                        component: 'ame-rev-code-editor',
                        bindings: { value: settingPath + '.css' },
                    }
                ],
                actions: [
                    {
                        t: "control",
                        kind: "link",
                        component: "ame-rev-event-button",
                        eventName: "adminMenuEditor:editObject",
                        iconClass: "dashicons dashicons-edit",
                        eventData: {
                            "t": "resolve",
                            "ref": {
                                "t": "binding",
                                "bind": settingPath
                            }
                        }
                    },
                    {
                        t: "control",
                        kind: "link",
                        component: "ame-rev-event-button",
                        eventName: "adminMenuEditor:deleteObject",
                        iconClass: "dashicons dashicons-trash",
                        classes: ["ame-delete-action-button"],
                        eventData: newTweakId
                    }
                ]
            }
        };
        console.log('New admin CSS snippet control to add:', newControl);
        //Add the new control to the admin CSS section. Usually, the last child is the "Add CSS Snippet"
        //button, so let's insert it before that.
        const children = this.adminCssSection.slots['default'];
        const totalChildren = children().length;
        children.splice(totalChildren - 1, 0, newControl);
        console.log('Added new admin CSS snippet control to the section:', this.adminCssSection);
    }
    getTweaksStructSetting() {
        const tweaks = this.mainUi.settings.getChild(RevisedUiDevVm.tweaksSettingId).getOrThrow();
        if (!(tweaks instanceof StructSetting)) {
            throw new Error('Tweaks setting is not a StructSetting');
        }
        return tweaks;
    }
    getDefaultCodeEditorParams() {
        if (this.cachedCodeEditorParams) {
            return this.cachedCodeEditorParams;
        }
        //Find the default admin CSS tweak. This is a linear search, but it's only done once,
        //and I expect it will only need to look at <50 nodes in the UI tree, so it should be fine.
        const path = ['twm-section_admin-css', 'ame-tweak-default-admin-css'];
        let currentElement = this.mainUi.rootComponent.params;
        for (const id of path) {
            for (const child of this.getDefaultSlotContent(currentElement)) {
                if (child.id === id) {
                    currentElement = child;
                    break;
                }
            }
            if (currentElement.id !== id) {
                throw new Error(`Default admin CSS snippet control not found at path: ${path.join(' -> ')}`);
            }
        }
        //This node should always have a child: a code editor control.
        if (this.getDefaultSlotContent(currentElement).length < 1) {
            throw new Error('Default admin CSS snippet control does not have a child code editor');
        }
        const firstChild = this.getDefaultSlotContent(currentElement)[0];
        if (!firstChild || firstChild.t !== 'control' || firstChild.component !== 'ame-rev-code-editor') {
            throw new Error('Default admin CSS snippet control does not have a child code editor');
        }
        //Grab everything except "id" and "bindings" from the code editor's params.
        const { id, bindings, ...paramsWithoutIdAndBindings } = firstChild;
        this.cachedCodeEditorParams = paramsWithoutIdAndBindings;
        return this.cachedCodeEditorParams;
    }
    getDefaultSlotContent(element) {
        if (element.slots && element.slots['default']) {
            return element.slots['default'];
        }
        else {
            return [];
        }
    }
    serializeTweakSettings() {
        const tweakSettingsId = 'ws_ame_tweak_settings--tweaks';
        const allSettings = this.mainUi.settings.serializeValue();
        const tweaks = allSettings[tweakSettingsId];
        if (!tweaks || (typeof tweaks !== 'object')) {
            return {};
        }
        return tweaks;
    }
    static slugify(input) {
        const _ = wsAmeLodash;
        let output = _.deburr(input);
        output = output.replace(/[^a-zA-Z0-9 _\-]/g, '');
        return _.kebabCase(output);
    }
}
RevisedUiDevVm.tweaksSettingId = 'ws_ame_tweak_settings--tweaks';
class AddUrlBlockDialog extends AmeBaseKnockoutDialog {
    constructor(add) {
        super();
        this.add = add;
        this.options.minWidth = 400;
        this.panelUi = new UiPack(wsRevisedUiData.addBlockUi);
        this.confirmButtonLabel = ko.observable('Add Block');
        this.isConfirmButtonEnabled = ko.pureComputed(() => {
            return !this.panelUi.hasValidationErrors();
        });
    }
    getTempUrlBlockSetting() {
        const opt = this.panelUi.settings.getChild('tempUrlBlock');
        if (!opt.isDefined()) {
            throw new Error('tempUrlBlock setting is not defined');
        }
        const tempBlockSetting = opt.get();
        if (tempBlockSetting instanceof StructSetting) {
            return tempBlockSetting;
        }
        else {
            throw new Error('Expected tempUrlBlock to be a StructSetting, but it was not: ' + tempBlockSetting);
        }
    }
    onConfirm(event) {
        super.onConfirm(event);
        const blockData = {
            ...this.getTempUrlBlockSetting().value(),
            enabledForActor: {}
        };
        this.add(blockData);
        this.isOpen(false);
    }
    onOpen() {
        console.log('AddUrlBlockDialog opened');
        //Reset state when the dialog opens.
        this.getTempUrlBlockSetting().updateWithoutValidation({
            title: '',
            urlList: '',
            matchType: 'auto',
            enabledForActor: {}
        });
    }
}
class EditAdminCssDialogV3 extends AmeBaseKnockoutDialog {
    constructor(manager) {
        super();
        this.manager = manager;
        this.autoCancelButton = true;
        this.selectedTweak = null;
        this.options.minWidth = 400;
        this.panelUi = new UiPack(wsRevisedUiData.editAdminCssUi);
        this.confirmButtonLabel = ko.observable('Add Snippet');
        this.isConfirmButtonEnabled = ko.pureComputed(() => {
            return !this.panelUi.hasValidationErrors();
        });
    }
    onOpen() {
        if (this.selectedTweak) {
            this.title('Edit admin CSS snippet');
            this.confirmButtonLabel('Save Changes');
            //Load the selected tweak's data into the temp setting for editing.
            this.getTempCssSnippetSetting().updateWithoutValidation(this.selectedTweak.value());
        }
        else {
            this.title('Add admin CSS snippet');
            this.confirmButtonLabel('Add Snippet');
            this.getTempCssSnippetSetting().updateWithoutValidation({
                label: '',
                css: '',
                enabledForActor: {},
                isUserDefined: true,
                typeId: 'admin-css'
            });
        }
    }
    onConfirm() {
        if (this.selectedTweak) {
            this.selectedTweak.value(this.getTempCssSnippetSetting().value());
        }
        else {
            this.manager.addAdminCssTweak(this.getTempCssSnippetSetting());
        }
        this.close();
    }
    onClose() {
        this.selectedTweak = null;
    }
    getTempCssSnippetSetting() {
        const opt = this.panelUi.settings.getChild('tempAdminCssSnippet');
        if (!opt.isDefined()) {
            throw new Error('tempAdminCssSnippet setting is not defined');
        }
        const tempSnippetSetting = opt.get();
        if (tempSnippetSetting instanceof StructSetting) {
            return tempSnippetSetting;
        }
        else {
            throw new Error('Expected tempAdminCssSnippet to be a StructSetting, but it was not: ' + tempSnippetSetting);
        }
    }
}
const vm = new RevisedUiDevVm(wsRevisedUiData);
window['wsAmeRevisedUiDevVm'] = vm;
const rootContainer = document.getElementById('ws-ame-revised-ui-container');
if (rootContainer === null) {
    throw new Error('Root container element not found');
}
registerRevisedUiComponents(ko);
ko.applyBindings(vm, rootContainer);
//# sourceMappingURL=revised-ui-dev.js.map