// Use global AppLogger for debug-controlled logging
const Logger = window.AppLogger || console;

export default class FormProperties {
    constructor(properties) {
        this.properties = properties;
        this.metadataProperties = {};
        this.categories = [];
        this.cataloguingCategoryKey = 'cataloguing';
        this.nodeContent = document.querySelector(
            '#main #workarea #node-content'
        );
        this.addBehaviourBodyToHideHelpDialogs();

        // Yjs properties binding instance
        this.yjsBinding = null;
    }

    isCheckedValue(value) {
        return value === true || value === 'true';
    }

    show() {
        this.combineMetadataProperties();
        const formElement = this.makeBodyElement(this.metadataProperties);
        this.setBodyElement(formElement);
        this.addBehaviourExeHelp();

        // Initialize Yjs binding for real-time sync
        this.initYjsBinding();

        setTimeout(() => {
            this.focusTextInput(
                this.nodeContent.querySelector('input[type="text"')
            );
        }, 500);
    }

    /**
     * Initialize Yjs binding for automatic property sync
     */
    initYjsBinding() {
        const project = this.properties.project;
        if (project._yjsBridge && project._yjsBridge.initialized) {
            const documentManager = project._yjsBridge.getDocumentManager();
            if (documentManager && documentManager.initialized && window.YjsPropertiesBinding) {
                // Cleanup previous binding if exists
                if (this.yjsBinding) {
                    this.yjsBinding.unbindForm();
                }

                // Create new binding
                this.yjsBinding = new window.YjsPropertiesBinding(documentManager);
                this.yjsBinding.bindForm(this.propertiesFormElement);

                Logger.log('[FormProperties] Yjs binding initialized - changes sync automatically');
            }
        }
    }

    combineMetadataProperties() {
        this.metadataProperties = {};
        this.metadataPropertiesBase = Object.assign(
            {},
            this.properties.properties,
            this.properties.cataloguing
        );
        if (
            eXeLearning.app.user.preferences.preferences.advancedMode.value ==
            'true'
        ) {
            this.metadataProperties = this.metadataPropertiesBase;
        } else {
            for (let [key, property] of Object.entries(
                this.metadataPropertiesBase
            )) {
                if (property.alwaysVisible)
                    this.metadataProperties[key] = property;
            }
        }
        return this.metadataProperties;
    }

    setBodyElement(bodyElement) {
        this.propertiesFormElement = this.nodeContent.querySelector(
            '#properties-node-content-form'
        );
        if (this.propertiesFormElement) {
            this.propertiesFormElement.replaceWith(bodyElement);
        } else {
            this.propertiesFormElement = bodyElement;
            this.nodeContent.append(this.propertiesFormElement);
        }
    }

    remove() {
        // Cleanup Yjs binding
        if (this.yjsBinding) {
            this.yjsBinding.unbindForm();
            this.yjsBinding = null;
        }
        if (this.propertiesFormElement) this.propertiesFormElement.remove();
    }

    makeBodyElement(properties) {
        const element = document.createElement('form');
        element.id = 'properties-node-content-form';
        element.classList.add('loading');
        element.setAttribute('novalidate', '');

        const formContentElement = document.createElement('div');
        formContentElement.classList.add('exe-properties-form-content');
        element.append(formContentElement);

        const propertiesTableElement = document.createElement('div');
        propertiesTableElement.classList.add('exe-table-content');
        propertiesTableElement.classList.add('pb-1');

        this.addRowsWithTabs(properties, propertiesTableElement);

        // No save button - changes sync automatically via Yjs
        formContentElement.append(propertiesTableElement);

        setTimeout(() => element.classList.remove('loading'), 100);

        return element;
    }

    /**
     * Create tabs structure for properties grouped by sections
     */
    addRowsWithTabs(properties, table) {
        // Define tab configuration
        const tabConfig = [
            { key: 'properties_package', title: _('Content metadata') },
            { key: 'export', title: _('Export options') },
            { key: 'custom_code', title: _('Custom code') },
            { key: 'screenshot', title: _('Screenshot'), custom: true },
        ];

        // Create tabs navigation
        const tabsNav = document.createElement('div');
        tabsNav.classList.add('project-properties-tabs');
        tabsNav.setAttribute('role', 'tablist');

        // Create tab content container
        const tabContent = document.createElement('div');
        tabContent.classList.add('project-properties-tab-content');

        // Group properties by their group key
        const groupedProperties = this.groupPropertiesByGroup(properties);

        // Create tabs and content panes
        tabConfig.forEach((tab, index) => {
            const isActive = index === 0;
            const tabId = `props-tab-${tab.key}`;
            const paneId = `props-pane-${tab.key}`;

            // Create tab button
            const tabButton = document.createElement('button');
            tabButton.type = 'button';
            tabButton.classList.add('project-properties-tab');
            if (isActive) tabButton.classList.add('active');
            tabButton.setAttribute('role', 'tab');
            tabButton.setAttribute('aria-selected', isActive ? 'true' : 'false');
            tabButton.setAttribute('aria-controls', paneId);
            tabButton.setAttribute('data-tab-target', paneId);
            tabButton.id = tabId;
            tabButton.textContent = tab.title;

            // Tab click behavior
            tabButton.addEventListener('click', () => {
                this.activateTab(tabsNav, tabContent, tabButton, paneId);
            });

            tabsNav.appendChild(tabButton);

            // Create tab pane
            const tabPane = document.createElement('div');
            tabPane.classList.add('project-properties-tab-pane');
            if (isActive) tabPane.classList.add('active');
            tabPane.setAttribute('role', 'tabpanel');
            tabPane.setAttribute('aria-labelledby', tabId);
            tabPane.id = paneId;

            // Add properties for this group
            if (tab.custom && tab.key === 'screenshot') {
                this.buildScreenshotPane(tabPane);
            } else {
                const groupProperties = groupedProperties.get(tab.key) || [];
                this.addPropertiesToPane(groupProperties, tabPane);
            }

            tabContent.appendChild(tabPane);
        });

        table.appendChild(tabsNav);
        table.appendChild(tabContent);
    }

    /**
     * Group properties by their group key
     */
    groupPropertiesByGroup(properties) {
        const grouped = new Map();
        let propertiesArray = Object.entries(properties);

        // Sort properties
        propertiesArray = propertiesArray.sort((a, b) => {
            if (
                a[1].multipleId &&
                b[1].multipleId &&
                a[1].multipleId === b[1].multipleId
            ) {
                if (a[1].multipleIndex === b[1].multipleIndex) return 0;
                return a[1].multipleIndex > b[1].multipleIndex ? 1 : -1;
            } else if (
                a[1].multipleId &&
                b[1].multipleId &&
                a[1].prefix === b[1].prefix
            ) {
                if (a[1].multipleIndex === b[1].multipleIndex) {
                    if (a[1].index === b[1].index) return 0;
                    return a[1].index > b[1].index ? 1 : -1;
                } else {
                    if (a[1].multipleIndex === b[1].multipleIndex) return 0;
                    return a[1].multipleIndex > b[1].multipleIndex ? 1 : -1;
                }
            } else {
                return 0;
            }
        });

        for (const [key, property] of propertiesArray) {
            let groupKey = '__no_group__';
            if (property.groups && Object.keys(property.groups).length) {
                groupKey = Object.keys(property.groups)[0];
            }

            if (!grouped.has(groupKey)) {
                grouped.set(groupKey, []);
            }
            grouped.get(groupKey).push([key, property]);
        }

        return grouped;
    }

    /**
     * Add properties to a tab pane
     */
    addPropertiesToPane(propertiesArray, pane) {
        const container = document.createElement('div');
        container.classList.add(
            'properties-group',
            'properties-body-container',
            'form-properties'
        );

        for (const [key, property] of propertiesArray) {
            const propertyRow = this.makeRowElement(key, property);
            if (propertyRow) container.appendChild(propertyRow);
        }

        pane.appendChild(container);
    }

    /**
     * Activate a tab and show its content pane
     */
    activateTab(tabsNav, tabContent, activeButton, activePaneId) {
        // Deactivate all tabs
        tabsNav.querySelectorAll('.project-properties-tab').forEach((tab) => {
            tab.classList.remove('active');
            tab.setAttribute('aria-selected', 'false');
        });

        // Deactivate all panes
        tabContent.querySelectorAll('.project-properties-tab-pane').forEach((pane) => {
            pane.classList.remove('active');
        });

        // Activate selected tab
        activeButton.classList.add('active');
        activeButton.setAttribute('aria-selected', 'true');

        // Activate selected pane
        const activePane = tabContent.querySelector(`#${activePaneId}`);
        if (activePane) {
            activePane.classList.add('active');
        }
    }
    addRowsFlatWithSectionTitles(properties, table) {
        let propertiesArray = Object.entries(properties);
        propertiesArray = propertiesArray.sort((a, b) => {
            if (
                a[1].multipleId &&
                b[1].multipleId &&
                a[1].multipleId === b[1].multipleId
            ) {
                if (a[1].multipleIndex === b[1].multipleIndex) return 0;
                return a[1].multipleIndex > b[1].multipleIndex ? 1 : -1;
            } else if (
                a[1].multipleId &&
                b[1].multipleId &&
                a[1].prefix === b[1].prefix
            ) {
                if (a[1].multipleIndex === b[1].multipleIndex) {
                    if (a[1].index === b[1].index) return 0;
                    return a[1].index > b[1].index ? 1 : -1;
                } else {
                    if (a[1].multipleIndex === b[1].multipleIndex) return 0;
                    return a[1].multipleIndex > b[1].multipleIndex ? 1 : -1;
                }
            } else {
                return 0;
            }
        });

        const groupContainers = new Map();

        const ensureGroupContainer = (topGroupKey, topGroupTitle, property) => {
            if (groupContainers.has(topGroupKey))
                return groupContainers.get(topGroupKey);

            const groupDiv = document.createElement('div');
            groupDiv.classList.add(
                'properties-group',
                'properties-body-container',
                'form-properties'
            );
            groupDiv.setAttribute('data-group', topGroupKey);

            const groupElementTitle = document.createElement('div');
            groupElementTitle.classList.add('properties-group-title');

            const collapseId = `collapse-${topGroupKey}`;
            groupElementTitle.setAttribute('data-bs-toggle', 'collapse');
            groupElementTitle.setAttribute('data-bs-target', `#${collapseId}`);
            groupElementTitle.setAttribute('role', 'button');
            Logger.log(topGroupKey, topGroupTitle, property);
            if (topGroupKey === 'properties_package') {
                groupElementTitle.setAttribute('aria-expanded', 'true');
            } else {
                groupElementTitle.classList.add('collapsed');
                groupElementTitle.setAttribute('aria-expanded', 'false');
            }
            groupElementTitle.setAttribute('aria-controls', collapseId);

            let titleText =
                "<span class='title-text'>" + _(topGroupTitle) + '</span>';
            const catKey = Object.keys(property.category || { '': '' })[0];
            if (catKey == this.cataloguingCategoryKey) {
                if (property.required) {
                    titleText =
                        '* ' +
                        titleText +
                        " · <span class='required-text'>(" +
                        _('Required') +
                        ')</span>';
                } else {
                    titleText +=
                        " · <span class='optional-text'>(" +
                        _('Optional') +
                        ')</span>';
                }
            }
            groupElementTitle.innerHTML =
                "<h2 class='title'>" + titleText + '</h2>';

            const collapseDiv = document.createElement('div');
            if (topGroupKey === 'properties_package') {
                collapseDiv.classList.add('collapse', 'show');
            } else {
                collapseDiv.classList.add('collapse');
            }

            collapseDiv.id = collapseId;

            groupDiv.append(groupElementTitle, collapseDiv);
            table.append(groupDiv);
            groupContainers.set(topGroupKey, collapseDiv);
            return collapseDiv;
        };

        for (const [key, property] of propertiesArray) {
            let topGroupKey = null;
            let topGroupTitle = null;
            if (property.groups && Object.keys(property.groups).length) {
                topGroupKey = Object.keys(property.groups)[0];
                topGroupTitle = property.groups[topGroupKey];
            }

            let groupContainer;
            if (topGroupKey) {
                groupContainer = ensureGroupContainer(
                    topGroupKey,
                    topGroupTitle,
                    property
                );
            } else {
                const noGroupKey = '__no_group__';
                if (!groupContainers.has(noGroupKey)) {
                    const g = document.createElement('div');
                    g.classList.add('properties-group');
                    g.setAttribute('data-group', 'no-group');
                    groupContainers.set(noGroupKey, g);
                    table.append(g);
                }
                groupContainer = groupContainers.get(noGroupKey);
            }

            const propertyRow = this.makeRowElement(key, property);
            if (propertyRow) groupContainer.append(propertyRow);
        }
    }

    makeRowElement(name, property) {
        property.id = name;
        const propertyId = property.multipleId
            ? property.multipleId
            : property.id;
        const propertyIdGenerated =
            propertyId + '-' + eXeLearning.app.common.generateId();

        const propertyRow = document.createElement('div');
        propertyRow.id = propertyIdGenerated + '-container';
        propertyRow.classList.add('property-row');
        propertyRow.setAttribute('property', property.id);
        propertyRow.setAttribute('type', property.type);
        propertyRow.setAttribute(
            'category',
            Object.keys(property.category || { '': '' })[0]
        );
        propertyRow.setAttribute(
            'group',
            property.groups ? Object.keys(property.groups).pop() : ''
        );
        propertyRow.setAttribute(
            'duplicate',
            property.duplicate ? property.duplicate : false
        );

        if (property.multipleId) {
            propertyRow.classList.add('copied-row');
        }

        const propertyTitle = this.makeRowElementLabel(
            propertyIdGenerated,
            property
        );
        const propertyValue = this.makeRowValueElement(
            propertyIdGenerated,
            propertyId,
            property
        );
        const helpContainer = this.makeRowElementHelp(property);
        const actionsContainer = this.makeRowActionsElement(
            property,
            propertyRow
        );
        if (actionsContainer && property.multipleId)
            actionsContainer.setAttribute('original', false);

        if (property.type == 'checkbox') {
            const item = document.createElement('span');
            item.classList.add('toggle-item');
            item.style.cursor = 'pointer';

            const control = document.createElement('span');
            control.classList.add('toggle-control');

            const visual = document.createElement('span');
            visual.classList.add('toggle-visual');
            visual.setAttribute('aria-hidden', 'true');

            propertyValue.classList.add('toggle-input');

            control.append(propertyValue, visual);

            propertyTitle.classList.add('toggle-label', 'mb-0');
            propertyTitle.style.cursor = 'pointer';

            item.addEventListener('click', (e) => {
                if (e.target !== propertyValue) {
                    e.preventDefault();
                    propertyValue.checked = !propertyValue.checked;
                    propertyValue.dispatchEvent(
                        new Event('change', { bubbles: true })
                    );
                }
            });
            propertyTitle.addEventListener('click', (e) => {
                e.preventDefault();
                e.stopPropagation();
                propertyValue.checked = !propertyValue.checked;
                propertyValue.dispatchEvent(
                    new Event('change', { bubbles: true })
                );
            });

            item.append(control, propertyTitle);
            propertyRow.append(item);

            if (helpContainer) {
                helpContainer.classList.add('ms-2');
                propertyRow.append(helpContainer);
            }
            if (actionsContainer) {
                actionsContainer.classList.add('ms-2');
                propertyRow.append(actionsContainer);
            }
        } else {
            const header = document.createElement('div');
            header.classList.add(
                'header-container',
                'd-flex',
                'align-items-center',
                'gap-2',
                'mb-1'
            );
            propertyTitle.classList.add('form-label', 'mb-0');
            header.append(propertyTitle);
            if (helpContainer) {
                header.append(helpContainer);
            }
            propertyRow.append(header);
            const controlStack = document.createElement('div');
            controlStack.classList.add(
                'd-flex',
                'align-items-center',
                'gap-2',
                'flex-nowrap',
                'content-field'
            );
            controlStack.append(propertyValue);
            if (actionsContainer) {
                actionsContainer.classList.add('mt-1');
                controlStack.append(actionsContainer);
            }
            propertyRow.append(controlStack);
        }

        return propertyRow;
    }

    makeRowElementLabel(id, property) {
        const propertyTitle = document.createElement('label');
        propertyTitle.setAttribute('for', id);

        // Translate the property title
        const translatedText = _(property.title);

        if (property.required) {
            // For required fields, use a span so DOMTranslator doesn't overwrite the asterisk
            propertyTitle.textContent = '* ';
            const textSpan = document.createElement('span');
            textSpan.setAttribute('data-i18n', property.title);
            textSpan.textContent = translatedText;
            propertyTitle.appendChild(textSpan);
        } else {
            // For non-required fields, translate the label directly
            propertyTitle.textContent = translatedText;
            if (property.title) {
                propertyTitle.setAttribute('data-i18n', property.title);
            }
        }

        return propertyTitle;
    }

    makeRowValueElement(id, name, property) {
        let valueElement;
        switch (property.type) {
            case 'text':
                valueElement = document.createElement('input');
                valueElement.value = property.value;
                break;
            case 'checkbox':
                valueElement = document.createElement('input');
                valueElement.checked = this.isCheckedValue(property.value);
                valueElement.classList.add('toggle-input');
                break;
            case 'date':
                valueElement = document.createElement('input');
                valueElement.value = property.value;
                break;
            case 'textarea':
                valueElement = document.createElement('textarea');
                valueElement.innerHTML = property.value;
                valueElement.value = property.value;
                break;
            case 'select': {
                valueElement = document.createElement('select');
                for (let [value, text] of Object.entries(
                    property.options || {}
                )) {
                    const optionElement = document.createElement('option');
                    optionElement.value = value;
                    optionElement.innerHTML = _(text);
                    if (value === property.value) {
                        optionElement.setAttribute('selected', 'selected');
                    }
                    valueElement.append(optionElement);
                }
                // Legacy license handling is done in YjsPropertiesBinding.updateInputFromYjs()
                // which runs after form creation and loads the actual value from Yjs
                break;
            }
            default:
                valueElement = document.createElement('div');
                break;
        }

        valueElement = this.addAttributesRowValueElement(
            id,
            name,
            property,
            valueElement
        );

        switch (property.type) {
            case 'select':
                valueElement.classList.add('form-select');
                break;
            case 'textarea':
                valueElement.classList.add('form-control');
                valueElement.setAttribute(
                    'rows',
                    property.rows ? property.rows : 3
                );
                break;
            case 'checkbox':
                break;
            case 'date':
            case 'text':
            default:
                valueElement.classList.add('form-control');
                break;
        }

        return valueElement;
    }

    addAttributesRowValueElement(id, name, property, valueElement) {
        valueElement.id = id;
        valueElement.setAttribute('name', id);
        valueElement.setAttribute('property', name);
        valueElement.setAttribute('type', property.type);
        valueElement.setAttribute(
            'category',
            property.category ? Object.keys(property.category)[0] : ''
        );
        valueElement.setAttribute(
            'group',
            property.groups ? Object.keys(property.groups).pop() : ''
        );
        valueElement.setAttribute('data-type', property.type);
        valueElement.classList.add('property-value');

        // Testing: stable data-testid for common properties
        const idToTestId = {
            titleNode: 'prop-title',
            editableInPage: 'prop-editable-in-page',
            visibility: 'prop-visible-export',
            description: 'prop-description',
            titlePage: 'prop-title-page',
            titleHtml: 'prop-title-html',
        };
        const kebab = (s) =>
            (s || '').replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
        const testId = idToTestId[property.id] || `prop-${kebab(property.id)}`;
        valueElement.setAttribute('data-testid', testId);

        valueElement.addEventListener('focus', () => this.hideHelpContentAll());

        if (property.required) {
            valueElement.setAttribute('required', '');
            valueElement.classList.add('required');
        }
        if (property.readonly) valueElement.setAttribute('readonly', '');

        if (property.onchange) {
            valueElement.addEventListener('change', () => {
                let value;
                switch (property.type) {
                    case 'select':
                        value =
                            valueElement.selectedOptions[0].innerHTML.trim();
                        break;
                    default:
                        value = valueElement.value.trim();
                        break;
                }
                this.propertiesFormElement.querySelector(
                    `#${property.onchange} input`
                ).value = value;
            });
        }
        return valueElement;
    }

    makeRowElementHelp(property) {
        if (property.help) {
            const helpContainer = document.createElement('div');
            helpContainer.classList.add(
                'exe-form-help',
                'help-content-disabled'
            );

            const helpIcon = document.createElement('span');
            helpIcon.classList.add(
                'form-help-exe-icon',
                'icon-medium',
                'info-icon-solid-green'
            );

            const helpSpanText = document.createElement('span');
            helpSpanText.classList.add('help-content', 'help-hidden');
            helpSpanText.innerHTML = _(property.help);

            helpContainer.append(helpIcon, helpSpanText);
            return helpContainer;
        } else {
            return false;
        }
    }

    makeRowActionsElement(property, row) {
        let actionsContainer = false;
        if (property.duplicate) {
            actionsContainer = document.createElement('div');
            actionsContainer.classList.add(
                'actions-duplicate-properties-container',
                'd-inline-flex',
                'align-items-center',
                'gap-2'
            );
            actionsContainer.setAttribute('duplicate', property.duplicate);
            actionsContainer.setAttribute('original', 'true');
            const actionAdd = document.createElement('div');
            actionAdd.classList.add('exe-icon', 'add-properties');
            actionAdd.setAttribute('duplicate', property.duplicate);
            actionAdd.innerHTML = 'add_circle_outline';
            this.addEventClickToActionAddButton(
                actionAdd,
                property.duplicate,
                property,
                row
            );
            actionsContainer.append(actionAdd);
            const actionDelete = document.createElement('div');
            actionDelete.classList.add('exe-icon', 'delete-properties');
            actionDelete.setAttribute('duplicate', property.duplicate);
            actionDelete.innerHTML = 'remove_circle_outline';
            this.addEventClickToActionDeleteButton(
                actionDelete,
                property.duplicate,
                property,
                row
            );
            actionsContainer.append(actionDelete);
        }
        return actionsContainer;
    }

    addEventClickToActionAddButton(button, duplicate, property, row) {
        button.addEventListener('click', () => {
            const rowsToDuplicate = [];
            let nextRow = row;
            for (let i = 0; i < duplicate; i++) {
                if (nextRow) {
                    const cloneRow = this.cloneRowElement(nextRow, property, i);
                    rowsToDuplicate.push(cloneRow);
                    if (i < duplicate - 1) nextRow = nextRow.nextElementSibling;
                }
            }
            rowsToDuplicate.reverse().forEach((cloneRowElement) => {
                this.insertAfter(nextRow, cloneRowElement);
                cloneRowElement
                    .querySelectorAll('.actions-duplicate-properties-container')
                    .forEach((actionsContainer) => {
                        const prevElement =
                            actionsContainer.parentNode.previousSibling;
                        if (actionsContainer && prevElement) {
                            const showRemoveButton =
                                prevElement.classList.contains(
                                    'property-row'
                                ) ||
                                cloneRowElement.classList.contains(
                                    'first-copied-row'
                                );
                            actionsContainer.setAttribute(
                                'original',
                                !showRemoveButton
                            );
                        }
                    });
            });
        });
    }

    addEventClickToActionDeleteButton(button, duplicate, property, row) {
        button.addEventListener('click', () => {
            const container = row.parentNode;
            const propertyId = row
                .querySelector('.property-value')
                .getAttribute('property');
            const isOriginal =
                button.parentNode.getAttribute('original') == 'true';
            const propertiesRows = container.querySelectorAll(
                `.property-value[property="${propertyId}"]`
            );
            const nPropertiesRows = propertiesRows ? propertiesRows.length : 0;

            if (nPropertiesRows > 1 && !isOriginal) {
                const rowsToDelete = [];
                let nextRow = row;
                for (let i = 0; i < duplicate; i++) {
                    if (
                        nextRow &&
                        nextRow != row &&
                        nextRow.classList.contains('first-copied-row')
                    )
                        break;
                    rowsToDelete.push(nextRow);
                    if (i < duplicate - 1)
                        nextRow = nextRow.nextElementSibling
                            ? nextRow.nextElementSibling
                            : false;
                }
                rowsToDelete.forEach((rowElement) => {
                    if (rowElement) rowElement.remove();
                });
            }
        });
    }

    cloneRowElement(row, propertyBase, num) {
        const cloneRow = row.cloneNode(true);
        const childrenLabel = cloneRow.querySelector('label');
        const childrenValue = cloneRow.querySelector('.property-value');
        const propertyId = cloneRow.getAttribute('property');
        const property = this.metadataProperties[propertyId];

        cloneRow.classList.add('copied-row');
        if (childrenLabel) childrenLabel.classList.add('copied');
        if (childrenValue) childrenValue.classList.add('copied');
        if (num == 0) cloneRow.classList.add('first-copied-row');
        else cloneRow.classList.remove('first-copied-row');

        cloneRow.id = `${cloneRow.id.split('-')[0]}-${eXeLearning.app.common.generateId()}-container`;

        const newId = `${row.id}-${eXeLearning.app.common.generateId()}`;
        if (childrenLabel) {
            childrenLabel.id = newId;
            childrenLabel.setAttribute('for', newId);
            childrenLabel.addEventListener('click', () => {
                childrenValue?.focus();
            });
        }
        if (childrenValue) {
            childrenValue.id = newId;
            childrenValue.setAttribute('name', newId);
            childrenValue.setAttribute(
                'groupCopied',
                propertyBase.groups
                    ? Object.keys(propertyBase.groups).pop()
                    : ''
            );
            if (childrenValue.tagName.toLowerCase() !== 'select')
                childrenValue.value = '';
        }

        // Note: No save action needed - changes sync automatically via Yjs
        const actionsContainer = cloneRow.querySelector(
            '.actions-duplicate-properties-container'
        );
        if (actionsContainer) {
            const nDuplicate = actionsContainer.getAttribute('duplicate');
            const buttonAdd = actionsContainer.querySelector('.add-properties');
            const buttonDelete =
                actionsContainer.querySelector('.delete-properties');
            this.addEventClickToActionAddButton(
                buttonAdd,
                nDuplicate,
                property,
                cloneRow
            );
            this.addEventClickToActionDeleteButton(
                buttonDelete,
                nDuplicate,
                property,
                cloneRow
            );
        }

        return cloneRow;
    }

    /*******************************************************************************
     * SCREENSHOT TAB
     *******************************************************************************/

    /**
     * Build the screenshot tab pane content
     * @param {HTMLElement} pane - The tab pane container
     */
    buildScreenshotPane(pane) {
        const container = document.createElement('div');
        container.classList.add('screenshot-panel', 'p-4');

        // === ROW: Preview (col-lg-7) + Info (col-lg-5) ===
        const row = document.createElement('div');
        row.classList.add('row', 'g-4');

        // --- Left column: preview card + buttons ---
        const leftCol = document.createElement('div');
        leftCol.classList.add('col-12', 'col-lg-7', 'd-flex', 'flex-column', 'align-items-center');

        // Preview card
        const previewCard = document.createElement('div');
        previewCard.classList.add('card', 'w-100', 'mb-3', 'shadow-sm');

        const previewCardBody = document.createElement('div');
        previewCardBody.classList.add('card-body', 'text-center', 'bg-light');

        const previewImg = document.createElement('img');
        previewImg.classList.add('img-fluid', 'border');
        previewImg.alt = _('Current project screenshot preview');
        previewImg.style.cssText = 'max-height:300px;object-fit:contain;display:none;';

        const noScreenshotText = document.createElement('p');
        noScreenshotText.classList.add('text-muted', 'fst-italic', 'py-5', 'mb-0');
        noScreenshotText.textContent = _('No screenshot yet. It will be auto-generated when you save or export.');

        previewCardBody.append(previewImg);
        previewCardBody.append(noScreenshotText);
        previewCard.append(previewCardBody);

        // Helper to update preview visibility consistently
        let removeBtn;
        const updatePreview = (screenshot) => {
            if (screenshot) {
                previewImg.src = screenshot;
                previewImg.style.display = 'block';
                noScreenshotText.style.display = 'none';
                if (removeBtn) removeBtn.style.display = '';
            } else {
                previewImg.src = '';
                previewImg.style.display = 'none';
                noScreenshotText.style.display = '';
                if (removeBtn) removeBtn.style.display = 'none';
            }
        };

        // Clean up previous observer if pane is rebuilt
        if (this._screenshotMetadata && this._screenshotObserver) {
            this._screenshotMetadata.unobserve(this._screenshotObserver);
            this._screenshotMetadata = null;
            this._screenshotObserver = null;
        }

        // Load current screenshot from Yjs and observe live changes
        const documentManager = this.properties.project?._yjsBridge?.getDocumentManager();
        if (documentManager) {
            const metadata = documentManager.getMetadata();
            updatePreview(metadata?.get('screenshot') || null);

            const observer = (event) => {
                if (event.keysChanged.has('screenshot')) {
                    updatePreview(metadata.get('screenshot') || null);
                }
            };
            metadata.observe(observer);
            this._screenshotMetadata = metadata;
            this._screenshotObserver = observer;
        }

        // Buttons row
        const buttonsRow = document.createElement('div');
        buttonsRow.classList.add('d-flex', 'flex-wrap', 'justify-content-center', 'gap-2', 'w-100');

        // Upload button
        const uploadBtn = document.createElement('button');
        uploadBtn.type = 'button';
        uploadBtn.classList.add('btn', 'btn-primary', 'd-flex', 'align-items-center');
        uploadBtn.setAttribute('aria-describedby', 'screenshot-help-text');
        uploadBtn.innerHTML = `<span class="auto-icon notranslate" aria-hidden="true">upload</span> ${_('Upload custom image')}`;

        const fileInput = document.createElement('input');
        fileInput.type = 'file';
        fileInput.accept = 'image/png,image/jpeg,image/webp';
        fileInput.style.display = 'none';

        uploadBtn.addEventListener('click', () => fileInput.click());

        fileInput.addEventListener('change', (event) => {
            const file = event.target.files[0];
            if (!file) return;

            if (file.size > 2 * 1024 * 1024) {
                eXeLearning.app.modals.alert.show({
                    title: _('File too large'),
                    body: _('Screenshot must be smaller than 2 MB.'),
                    contentId: 'warning',
                });
                return;
            }

            const reader = new FileReader();
            reader.onload = (e) => {
                const img = new Image();
                img.onload = () => {
                    const ratio = img.naturalWidth / img.naturalHeight;
                    const is16x9 = Math.abs(ratio - 16 / 9) < 0.05;
                    const hasMinWidth = img.naturalWidth >= 600;
                    if (!is16x9 || !hasMinWidth) {
                        eXeLearning.app.modals.alert.show({
                            title: _('Invalid image'),
                            body: _('The image does not meet the minimum requirements: 16:9 aspect ratio and at least 600 pixels wide.'),
                            contentId: 'warning',
                        });
                        fileInput.value = '';
                        return;
                    }
                    const pngDataUrl = this.resizeAndConvertToPng(img);
                    this.setScreenshot(pngDataUrl);
                };
                img.src = e.target.result;
            };
            reader.readAsDataURL(file);
            fileInput.value = '';
        });

        // Regenerate button
        const regenerateBtn = document.createElement('button');
        regenerateBtn.type = 'button';
        regenerateBtn.classList.add('btn', 'btn-outline-secondary', 'd-flex', 'align-items-center');
        regenerateBtn.innerHTML = `<span class="auto-icon notranslate" aria-hidden="true">refresh</span> ${_('Generate from content')}`;

        regenerateBtn.addEventListener('click', async () => {
            const bridge = this.properties.project?._yjsBridge;
            if (!bridge?.generateScreenshotFromFirstPage) {
                eXeLearning.app.modals.alert.show({
                    title: _('Not available'),
                    body: _('Screenshot generation is not available.'),
                    contentId: 'warning',
                });
                return;
            }

            const doRegenerate = async () => {
                // Clear existing screenshot so auto-generation runs
                const dm = bridge.getDocumentManager();
                if (dm) {
                    dm.getMetadata().delete('screenshot');
                }

                regenerateBtn.disabled = true;
                regenerateBtn.innerHTML = `<span class="auto-icon notranslate" aria-hidden="true">refresh</span> ${_('Generating...')}`;

                try {
                    await bridge.generateScreenshotFromFirstPage();
                } catch (error) {
                    console.error('[FormProperties] Screenshot regeneration failed:', error);
                    eXeLearning.app.modals.alert.show({
                        title: _('Generation failed'),
                        body: _('Could not generate screenshot from content. Try uploading an image instead.'),
                        contentId: 'warning',
                    });
                } finally {
                    regenerateBtn.disabled = false;
                    regenerateBtn.innerHTML = `<span class="auto-icon notranslate" aria-hidden="true">refresh</span> ${_('Generate from content')}`;
                }
            };

            const hasScreenshot = previewImg.style.display !== 'none' && previewImg.src;
            if (hasScreenshot) {
                eXeLearning.app.modals.confirm.show({
                    title: _('Replace screenshot'),
                    body: _('This will delete the current image. Do you want to continue?'),
                    confirmButtonText: _('Continue'),
                    cancelButtonText: _('Cancel'),
                    confirmExec: doRegenerate,
                });
            } else {
                await doRegenerate();
            }
        });

        // Remove button
        removeBtn = document.createElement('button');
        removeBtn.type = 'button';
        removeBtn.classList.add('btn', 'btn-outline-secondary', 'd-flex', 'align-items-center');
        removeBtn.innerHTML = `<span class="auto-icon notranslate" aria-hidden="true">delete</span> ${_('Delete')}`;
        if (!previewImg.src || previewImg.style.display === 'none') {
            removeBtn.style.display = 'none';
        }

        removeBtn.addEventListener('click', () => {
            eXeLearning.app.modals.confirm.show({
                title: _('Delete screenshot'),
                body: _('Delete the current image? This action cannot be undone.'),
                confirmButtonText: _('Delete'),
                cancelButtonText: _('Cancel'),
                confirmExec: () => {
                    updatePreview(null);
                    const dm = this.properties.project?._yjsBridge?.getDocumentManager();
                    if (dm) {
                        dm.getMetadata().delete('screenshot');
                    }
                },
            });
        });

        buttonsRow.append(fileInput);
        buttonsRow.append(uploadBtn);
        buttonsRow.append(regenerateBtn);
        buttonsRow.append(removeBtn);

        leftCol.append(previewCard);
        leftCol.append(buttonsRow);

        // --- Right column: info panel ---
        const rightCol = document.createElement('div');
        rightCol.classList.add('col-12', 'col-lg-5');

        const infoAlert = document.createElement('div');
        infoAlert.classList.add('alert', 'alert-light', 'd-flex');
        infoAlert.id = 'screenshot-help-text';
        infoAlert.setAttribute('role', 'note');
        infoAlert.innerHTML = `
            <div>
                <h5 class="alert-heading lead mb-3">${_('Recommendations')}</h5>
                <p class="mb-2 small">
                    ${_('Use a 16:9 image (1280×720 px recommended) that clearly represents the main content of the learning resource. Avoid clutter and small text, and ensure good contrast for readability at small sizes.')}
                </p>
                <p class="mb-0 small text-muted">
                    ${_('The image will be used as a preview of this educational resource across different platforms.')}
                </p>
            </div>
        `;

        rightCol.append(infoAlert);

        row.append(leftCol);
        row.append(rightCol);
        container.append(row);

        pane.appendChild(container);
    }

    /**
     * Resize image and convert to PNG data URL (max 1280x720)
     */
    resizeAndConvertToPng(img) {
        const canvas = document.createElement('canvas');
        let width = img.width;
        let height = img.height;
        const maxWidth = 1280;
        const maxHeight = 720;
        if (width > maxWidth || height > maxHeight) {
            const ratio = Math.min(maxWidth / width, maxHeight / height);
            width = Math.round(width * ratio);
            height = Math.round(height * ratio);
        }
        canvas.width = width;
        canvas.height = height;
        const ctx = canvas.getContext('2d');
        ctx.drawImage(img, 0, 0, width, height);
        return canvas.toDataURL('image/png');
    }

    /**
     * Set screenshot in preview and Yjs metadata
     */
    setScreenshot(pngDataUrl) {
        // Setting Yjs metadata triggers the observer which updates the UI
        const dm = this.properties.project?._yjsBridge?.getDocumentManager();
        if (dm) {
            dm.getMetadata().set('screenshot', pngDataUrl);
        }
    }

    /*******************************************************************************
     * BEHAVIOUR
     *******************************************************************************/

    addBehaviourExeHelp() {
        const exeHelp = this.nodeContent.querySelectorAll('.exe-form-help');
        exeHelp.forEach((help) => {
            const helpContent = help.querySelector('.help-content');
            help.setAttribute('title', _('Information'));
            this.hideHelpContent(help);
            help.querySelector('.form-help-exe-icon').addEventListener(
                'click',
                () => {
                    const show = helpContent.classList.contains('help-hidden');
                    this.hideHelpContentAll();
                    if (show) this.showHelpContent(help);
                }
            );
        });
    }

    addBehaviourBodyToHideHelpDialogs() {
        document.querySelector('body').addEventListener('click', (event) => {
            if (!event.target.classList.contains('form-help-exe-icon'))
                this.hideHelpContentAll();
        });
    }

    showHelpContent(helpContainer) {
        const helpContent = helpContainer.querySelector('.help-content');
        helpContent.classList.remove('help-hidden');
        helpContainer.classList.add('help-content-active');
        helpContainer.classList.remove('help-content-disabled');
    }

    hideHelpContent(helpContainer) {
        const helpContent = helpContainer.querySelector('.help-content');
        helpContent.classList.add('help-hidden');
        helpContainer.classList.add('help-content-disabled');
        helpContainer.classList.remove('help-content-active');
    }

    hideHelpContentAll() {
        const exeHelp = this.nodeContent.querySelectorAll('.exe-form-help');
        exeHelp.forEach((help) => this.hideHelpContent(help));
    }

    focusTextInput(input) {
        if (input) {
            input.focus();
            const inputElementValue = input.value;
            input.value = '';
            input.value = inputElementValue;
        }
    }

    insertAfter(referenceNode, newNode) {
        referenceNode.parentNode.insertBefore(
            newNode,
            referenceNode.nextSibling
        );
    }

    reloadValues() {
        this.combineMetadataProperties();
        for (let [key, property] of Object.entries(this.metadataProperties)) {
            let element;
            if (property.multipleId) {
                const elementsMultiples = this.nodeContent.querySelectorAll(
                    `.property-value[property="${property.multipleId}"]`
                );
                element = elementsMultiples[property.multipleIndex - 1];
            } else {
                element = this.nodeContent.querySelector(
                    `.property-value[property="${key}"]`
                );
            }
            if (!element) continue;
            switch (property.type) {
                case 'checkbox':
                    element.checked = this.isCheckedValue(property.value);
                    break;
                case 'select': {
                    const select = element.querySelector(
                        `option[value="${property.value}"]`
                    );
                    if (select) select.setAttribute('selected', 'selected');
                    break;
                }
                case 'text':
                case 'date':
                case 'textarea':
                default:
                    element.value = property.value;
                    break;
            }
        }
    }
}
