(() => {
    'use strict';

    window.FotogenicAI = window.FotogenicAI || {};
    const Studio = window.FotogenicAI.Studio = window.FotogenicAI.Studio || {};
    const { __, _n, sprintf } = Studio.i18n;
    const vm = Studio.viewModel;
    const progress = Studio.progress;
    const icons = window.FotogenicAI.Shared?.ui?.icon;
    if (!icons) throw new Error('Fotogenic AI shared icon helper is required.');

    const RUN_STATUSES = new Set([
        'loading', 'queued', 'starting', 'processing', 'finalizing', 'saving', 'pausing', 'paused',
		'stopping', 'stopped', 'uncertain', 'partial', 'completed', 'failed',
    ]);
	const ITEM_STATUSES = new Set([
        'queued', 'starting', 'processing', 'finalizing', 'saving', 'pausing', 'paused', 'stopping', 'stopped',
		'uncertain', 'partial', 'completed', 'failed', 'skipped', 'removed',
    ]);
	const ACTIVE_ITEM_STATUSES = new Set(['starting', 'processing', 'finalizing', 'saving', 'paused']);
	const COMPLETE_ITEM_STATUSES = new Set(['completed']);

    const normalizeStatus = (value, allowed, fallback) => {
        const raw = vm.cleanText(value, 32).toLowerCase().replaceAll('_', '-');
        return allowed.has(raw) ? raw : fallback;
    };

    const normalizeItem = (value = {}, index = 0) => {
        const status = normalizeStatus(value.status, ITEM_STATUSES, 'uncertain');
        const totalOutputs = vm.nonNegativeInteger(value.totalOutputs, 0, 100);
        const completedOutputs = Math.min(
            totalOutputs || 100,
            vm.nonNegativeInteger(value.completedOutputs, 0, 100)
        );
        const subjectId = vm.positiveInteger(value.subjectId);
        return Object.freeze({
            key: vm.cleanText(value.key ?? value.itemId, 100) || `item-${index + 1}`,
            itemId: vm.positiveInteger(value.itemId),
            subjectId,
            itemOrdinal: vm.positiveInteger(value.itemOrdinal, index + 1, 100000),
            label: vm.cleanText(value.label ?? value.title ?? value.name, 200) || sprintf( __( 'Item %d', 'fotogenic-ai' ), index + 1 ),
            meta: vm.cleanText(value.meta, 220) || (subjectId
                ? sprintf( __( 'ID %d', 'fotogenic-ai' ), subjectId )
                : __( 'Exact accepted source', 'fotogenic-ai' )),
            imageUrl: vm.safeUrl(value.imageUrl ?? value.thumbUrl),
            status,
            totalOutputs,
            completedOutputs,
            failedOutputs: vm.nonNegativeInteger(value.failedOutputs, 0, 100),
            message: vm.cleanText(value.message, 300),
            result: value.result && typeof value.result === 'object' && !Array.isArray(value.result) ? value.result : null,
            attachments: Array.isArray(value.attachments) ? value.attachments.slice(0, 10) : [],
			updatedAt: vm.nonNegativeInteger(value.updatedAt, 0, Number.MAX_SAFE_INTEGER),
            finishedAt: vm.nonNegativeInteger(value.finishedAt, 0, Number.MAX_SAFE_INTEGER),
        });
    };

    const orderItems = (items) => items
        .map((item, stableIndex) => ({ item, stableIndex }))
        .sort((leftEntry, rightEntry) => {
            const left = leftEntry.item;
            const right = rightEntry.item;
            return left.itemOrdinal - right.itemOrdinal || left.itemId - right.itemId || leftEntry.stableIndex - rightEntry.stableIndex;
        })
        .map(({ item }) => item);

    const normalizeOutputCounts = (value, items) => {
        const derived = items.reduce((counts, item) => ({
            total: counts.total + item.totalOutputs,
            completed: counts.completed + item.completedOutputs,
            failed: counts.failed + item.failedOutputs,
        }), { total: 0, completed: 0, failed: 0 });
        const source = value && typeof value === 'object' ? value : {};
        return Object.freeze({
            total: Math.max(derived.total, vm.nonNegativeInteger(source.total, derived.total, 100000)),
            completed: Math.max(derived.completed, vm.nonNegativeInteger(source.completed, derived.completed, 100000)),
            failed: Math.max(derived.failed, vm.nonNegativeInteger(source.failed, derived.failed, 100000)),
        });
    };

    const normalizeBulk = (value = {}) => {
        const status = normalizeStatus(value.status, RUN_STATUSES, 'loading');
        const statusReason = vm.safeCode(value.statusReason);
        const authorityChanged = status === 'paused' && statusReason === 'authority_changed';
        const items = orderItems((Array.isArray(value.items) ? value.items : []).slice(0, 100).map(normalizeItem));
        const page = vm.positiveInteger(value.page, 1, 1000);
        const hasNext = value.hasNext === true;
        const totalPages = Math.max(
            page + (hasNext ? 1 : 0),
            vm.positiveInteger(value.totalPages, 1, 1000)
        );
        return Object.freeze({
			...vm.normalizeRoute(value),
			status,
			deliveryMode: vm.cleanText(value.deliveryMode, 32).toLowerCase(),
            statusReason,
            items,
			allResultsRemoved: value.allResultsRemoved === true
				&& items.length > 0
				&& items.every((item) => item.status === 'removed'),
            page,
            totalPages,
            hasNext,
            totalItems: Math.max(items.length, vm.nonNegativeInteger(value.totalItems, items.length, 100000)),
            outputCounts: normalizeOutputCounts(value.outputCounts, items),
            pollIntervalSeconds: Math.max(0, Math.min(60, Number(value.pollIntervalSeconds) || 0)),
            loading: value.loading === true,
            error: vm.cleanText(value.error, 400),
            controls: Object.freeze({
                checkStatus: value.controls?.checkStatus === true
                    && (status === 'uncertain' || items.length === 0),
                pause: value.controls?.pause === true,
                resume: value.controls?.resume === true && !authorityChanged,
                reviewAuthority: value.controls?.reviewAuthority === true || authorityChanged,
                stop: value.controls?.stop === true,
            }),
        });
    };

    const itemActionKind = (item, handlers = {}) => {
        if (item.completedOutputs > 0 && item.result && typeof handlers.viewItem === 'function') return 'view';
        return 'none';
    };

    const createBulkView = ({ mount: initialMount, announce = () => {} } = {}) => {
        let mount = initialMount || null;
        let current = null;
        let handlers = {};
        let pending = '';
        let actionError = '';
        let lastStatus = '';
		let lastPresentationSignature = '';
        let restoreFocusKey = '';
        let stopLayer = null;
        let stopTrigger = null;
        let stopCloseTimer = 0;
        let lockedNodes = [];
        let destroyed = false;

        const setMount = (nextMount) => {
            if (mount === (nextMount || null)) return;
            closeStopDialog({ restore: false, immediate: true });
            mount = nextMount || null;
			lastPresentationSignature = '';
            const requestedFocus = mount?.getAttribute?.('data-fa-restore-focus-key');
            if (requestedFocus) {
                restoreFocusKey = String(requestedFocus);
                mount.removeAttribute?.('data-fa-restore-focus-key');
            }
        };

        const activeFocusKey = () => {
            const active = document.activeElement;
            return active && mount?.contains?.(active)
                ? String(active.getAttribute?.('data-fa-focus-key') || '')
                : '';
        };

        const restoreFocus = () => {
            if (!restoreFocusKey || !mount) return;
            const workspace = mount.closest?.('.fotogenic-ai-progress-workspace');
            const target = workspace
                ? [...workspace.querySelectorAll('[data-fa-focus-key]')]
                    .find((node) => node.getAttribute?.('data-fa-focus-key') === restoreFocusKey && !node.disabled && !node.hidden)
                : null;
            if (target?.focus) {
                target.focus({ preventScroll: true });
                restoreFocusKey = '';
            } else if (!pending) {
                restoreFocusKey = '';
                workspace?.querySelector?.('.fotogenic-ai-progress-intro h2')?.focus?.({ preventScroll: true });
            }
        };

        const invoke = async (name, callback, payload, navigation = false) => {
            if (destroyed || pending || typeof callback !== 'function') return;
            pending = name;
            actionError = '';
            renderCurrent();
            let navigated = false;
            try {
                await callback(payload);
                navigated = navigation;
            } catch (_) {
                actionError = __( 'The bulk action could not be completed. Refresh the current run before trying again.', 'fotogenic-ai' );
                announce(actionError);
            } finally {
                pending = '';
                if (!destroyed && !navigated) renderCurrent();
            }
        };

        const createAction = (label, name, callback, payload, { navigation = false, primary = false, icon = null } = {}) => {
            const control = vm.button(
                pending === name ? sprintf( __( '%s…', 'fotogenic-ai' ), label ) : label,
                primary ? 'primary' : 'secondary'
            );
            control.setAttribute('data-fa-focus-key', `bulk:${name}`);
            control.disabled = Boolean(pending);
            control.setAttribute('aria-busy', pending === name ? 'true' : 'false');
            if (icon) {
                const graphic = icons.create(icon.name, { weight: icon.weight || 'regular', size: icon.size || 16 });
                if (icon.append === true) control.appendChild(graphic);
                else control.prepend(graphic);
            }
            control.addEventListener('click', () => void invoke(name, callback, payload, navigation));
            return control;
        };

        const unlockWorkspace = () => {
            lockedNodes.forEach(({ node, inert, ariaHidden }) => {
                node.inert = inert;
                if (ariaHidden === null) node.removeAttribute('aria-hidden');
                else node.setAttribute('aria-hidden', ariaHidden);
            });
            lockedNodes = [];
            stopLayer?.closest?.('.fotogenic-ai-progress-workspace')?.classList.remove('has-progress-dialog');
            document.documentElement?.classList?.remove('fotogenic-ai-progress-dialog-open');
            document.body?.classList?.remove('fotogenic-ai-progress-dialog-open');
        };

        function closeStopDialog({ restore = true, immediate = false } = {}) {
            if (!stopLayer) return;
            const trigger = stopTrigger;
            const layer = stopLayer;
            const finish = () => {
                stopCloseTimer = 0;
                unlockWorkspace();
                layer.remove();
                if (stopLayer === layer) stopLayer = null;
                stopTrigger = null;
                if (restore) window.setTimeout(() => trigger?.focus?.({ preventScroll: true }), 0);
            };
            window.clearTimeout(stopCloseTimer);
            const delay = immediate || window.matchMedia?.('(prefers-reduced-motion: reduce)')?.matches ? 0 : 180;
            if (!delay) {
                finish();
                return;
            }
            layer.classList.add('is-closing');
            stopCloseTimer = window.setTimeout(finish, delay);
        }

        const openStopDialog = (trigger) => {
            if (!mount || stopLayer || typeof handlers.stop !== 'function') return;
            const workspace = mount.closest?.('.fotogenic-ai-progress-workspace');
            if (!workspace) return;
            stopTrigger = trigger;
            stopLayer = vm.element('div', 'fotogenic-ai-progress-confirmation-layer');
            const dialog = vm.element('section', 'fotogenic-ai-progress-confirmation-dialog');
            dialog.setAttribute('role', 'alertdialog');
            dialog.setAttribute('aria-modal', 'true');
            dialog.setAttribute('aria-labelledby', 'fotogenic-ai-stop-run-title');
            dialog.setAttribute('aria-describedby', 'fotogenic-ai-stop-run-description');
            const header = vm.element('header');
            const icon = vm.element('span', 'fotogenic-ai-progress-confirmation-icon');
            icon.appendChild(icons.create('stop', { weight: 'fill', size: 16 }));
            const copy = vm.element('div');
            const title = vm.element('h2', '', __( 'Stop this bulk run?', 'fotogenic-ai' ));
            title.id = 'fotogenic-ai-stop-run-title';
            const description = vm.element('p', '', __( 'Active items will finish first. Files already saved in Media Library will be kept.', 'fotogenic-ai' ));
            description.id = 'fotogenic-ai-stop-run-description';
            copy.append(title, description);
            header.append(icon, copy);
            const footer = vm.element('footer');
            const cancel = vm.button(__( 'Cancel', 'fotogenic-ai' ), 'fotogenic-ai-progress-dialog-cancel');
            const stop = vm.button(__( 'Stop run', 'fotogenic-ai' ), 'fotogenic-ai-progress-dialog-danger');
            cancel.addEventListener('click', () => closeStopDialog());
            stop.addEventListener('click', () => {
                closeStopDialog({ restore: false });
                void invoke('stop', handlers.stop, current).finally(() => {
                    mount?.closest?.('.fotogenic-ai-progress-workspace')
                        ?.querySelector?.('.fotogenic-ai-progress-intro h2')
                        ?.focus?.({ preventScroll: true });
                });
            });
            footer.append(cancel, stop);
            dialog.append(header, footer);
            stopLayer.appendChild(dialog);
            stopLayer.addEventListener('mousedown', (event) => {
                if (event.target === stopLayer) closeStopDialog();
            });
            stopLayer.addEventListener('keydown', (event) => {
                if (event.key === 'Escape') {
                    event.preventDefault();
                    closeStopDialog();
                    return;
                }
                if (event.key !== 'Tab') return;
                const focusable = [cancel, stop].filter((control) => !control.disabled);
                const first = focusable[0];
                const last = focusable[focusable.length - 1];
                if (event.shiftKey && document.activeElement === first) {
                    event.preventDefault();
                    last.focus();
                } else if (!event.shiftKey && document.activeElement === last) {
                    event.preventDefault();
                    first.focus();
                }
            });
            lockedNodes = [...workspace.children].map((node) => ({
                node,
                inert: node.inert === true,
                ariaHidden: node.getAttribute('aria-hidden'),
            }));
            lockedNodes.forEach(({ node }) => {
                node.inert = true;
                node.setAttribute('aria-hidden', 'true');
            });
            workspace.classList.add('has-progress-dialog');
            document.documentElement?.classList?.add('fotogenic-ai-progress-dialog-open');
            document.body?.classList?.add('fotogenic-ai-progress-dialog-open');
            workspace.appendChild(stopLayer);
            window.requestAnimationFrame(() => stopLayer?.classList.add('is-open'));
            window.setTimeout(() => cancel.focus({ preventScroll: true }), 0);
        };

        const renderControls = () => {
            const host = mount?.closest?.('.fotogenic-ai-progress-workspace')?.querySelector?.('[data-fa-progress-controls]');
            if (!host || !current) return;
            const controls = [];
            if (current.controls.checkStatus && typeof handlers.checkStatus === 'function') {
                controls.push(createAction(__( 'Check status', 'fotogenic-ai' ), 'checkStatus', handlers.checkStatus, current, { primary: true, icon: { name: 'arrows-clockwise' } }));
            }
            if (['processing', 'finalizing', 'saving'].includes(current.status) && current.controls.pause && typeof handlers.pause === 'function') {
                controls.push(createAction(__( 'Pause', 'fotogenic-ai' ), 'pause', handlers.pause, current, { icon: { name: 'pause', weight: 'fill' } }));
            }
            if (current.status === 'paused' && current.controls.resume && typeof handlers.resume === 'function') {
                controls.push(createAction(__( 'Resume', 'fotogenic-ai' ), 'resume', handlers.resume, current, { primary: true, icon: { name: 'play', weight: 'fill' } }));
            }
            if (current.status === 'paused' && current.controls.reviewAuthority && typeof handlers.reviewAuthority === 'function') {
                controls.push(createAction(__( 'Review current request', 'fotogenic-ai' ), 'reviewAuthority', handlers.reviewAuthority, current, { navigation: true, primary: true }));
            }
            if (
                ['processing', 'finalizing', 'saving', 'paused'].includes(current.status)
                && current.controls.stop
                && typeof handlers.stop === 'function'
            ) {
                const stop = vm.button(__( 'Stop', 'fotogenic-ai' ), 'secondary fotogenic-ai-progress-stop');
                stop.setAttribute('data-fa-focus-key', 'bulk:stop');
                stop.disabled = Boolean(pending);
                stop.prepend(icons.create('stop', { weight: 'fill', size: 16 }));
                stop.addEventListener('click', () => openStopDialog(stop));
                controls.push(stop);
            }
            if (
                ['stopped', 'partial', 'completed', 'failed'].includes(current.status)
                && typeof handlers.openSummary === 'function'
            ) {
                controls.push(createAction(__( 'Open summary', 'fotogenic-ai' ), 'openSummary', handlers.openSummary, current, { navigation: true, primary: true, icon: { name: 'arrow-right', append: true } }));
            }
            host.replaceChildren(...controls);
        };

        const appendSource = (container, item) => {
            const media = vm.element('span', 'fotogenic-ai-progress-source__media');
            if (item.imageUrl) {
                const image = vm.element('img');
                image.src = item.imageUrl;
                image.alt = '';
                image.decoding = 'async';
                media.appendChild(image);
            } else {
                media.appendChild(icons.create('image-square', { size: 24 }));
            }
            const copy = vm.element('span', 'fotogenic-ai-progress-source__copy');
            copy.append(vm.element('strong', '', item.label), vm.element('small', '', item.meta));
            container.append(media, copy);
        };

        const itemStatusLabel = (item) => {
            if (item.presentationStatus === 'starting') return __( 'Starting', 'fotogenic-ai' );
            if (COMPLETE_ITEM_STATUSES.has(item.status)) {
                return item.totalOutputs
                    ? sprintf( __( '%1$d of %2$d saved', 'fotogenic-ai' ), item.completedOutputs, item.totalOutputs )
                    : __( 'Saved', 'fotogenic-ai' );
            }
            return progress.statusLabel(item.status);
        };

        const createItemAction = (item) => {
            const actionKind = itemActionKind(item, handlers);
            if (actionKind === 'none') return null;
            const actions = {
                view: [__( 'View results', 'fotogenic-ai' ), handlers.viewItem, { navigation: true }],
            };
            const [label, callback, options] = actions[actionKind];
            const control = createAction(label, `${actionKind}:${item.key}`, callback, item, options);
            control.className = 'fotogenic-ai-progress-item-action';
            return control;
        };

        const createQueueRow = (item, isCurrent) => {
            const displayStatus = item.presentationStatus || item.status;
            const row = vm.element('article', `fotogenic-ai-progress-row is-${displayStatus}${isCurrent ? ' is-current' : ''}`);
            row.setAttribute('data-fa-render-key', `bulk:row:${item.key}`);
            if (isCurrent) row.setAttribute('aria-current', 'step');
            const source = vm.element('div', 'fotogenic-ai-progress-source');
            source.setAttribute('data-fa-render-key', `bulk:source:${item.key}`);
            source.setAttribute('data-fa-preserve-children', '');
            appendSource(source, item);
            const output = vm.element('div', 'fotogenic-ai-progress-output');
            output.setAttribute('data-fa-render-key', `bulk:output:${item.key}`);
            if (item.totalOutputs) {
				output.appendChild(vm.element('span', '', sprintf( __( '%1$d of %2$d', 'fotogenic-ai' ), item.completedOutputs, item.totalOutputs )));
				if (!['queued', 'starting'].includes(displayStatus)) {
					output.appendChild(progress.createProgressBar({
						completed: item.completedOutputs,
						total: item.totalOutputs,
						active: ACTIVE_ITEM_STATUSES.has(displayStatus) && displayStatus !== 'paused',
						renderKey: `bulk:progress:${item.key}`,
					}));
				}
            } else {
				output.appendChild(vm.element('span', '', __( 'Pending', 'fotogenic-ai' )));
            }
            const status = vm.element('div', 'fotogenic-ai-progress-item-status');
            status.setAttribute('data-fa-render-key', `bulk:status:${item.key}`);
            const icon = icons.create(progress.statusIconName(displayStatus), {
                weight: progress.statusIconWeight(displayStatus),
                size: 18,
            });
			icon.setAttribute('data-fa-render-key', `bulk:status-icon:${item.key}:${displayStatus}`);
			if (ACTIVE_ITEM_STATUSES.has(displayStatus) && displayStatus !== 'paused') icon.classList.add('fotogenic-ai-icon--spin');
            const copy = vm.element('span');
            copy.appendChild(vm.element('strong', '', itemStatusLabel(item)));
            if (item.message) copy.appendChild(vm.element('small', '', item.message));
            status.append(icon, copy);
            const action = createItemAction(item);
            if (action) status.appendChild(action);
            row.append(source, output, status);
            return row;
        };

		const presentationSignature = () => JSON.stringify({
			status: current.status,
			statusReason: current.statusReason,
			page: current.page,
			totalPages: current.totalPages,
			hasNext: current.hasNext,
			totalItems: current.totalItems,
			allResultsRemoved: current.allResultsRemoved,
			outputCounts: current.outputCounts,
			loading: current.loading,
			error: current.error,
			controls: current.controls,
			pending,
			actionError,
			handlerCapabilities: Object.fromEntries([
				'checkStatus', 'pause', 'resume', 'reviewAuthority', 'stop', 'openSummary', 'viewItem', 'page',
			].map((name) => [name, typeof handlers[name] === 'function'])),
			items: current.items.map((item) => ({
				key: item.key,
				itemId: item.itemId,
				subjectId: item.subjectId,
				itemOrdinal: item.itemOrdinal,
				label: item.label,
				meta: item.meta,
				imageUrl: item.imageUrl,
				status: item.status,
				totalOutputs: item.totalOutputs,
				completedOutputs: item.completedOutputs,
				failedOutputs: item.failedOutputs,
				message: item.message,
				hasResult: Boolean(item.result),
				attachmentIds: item.attachments.map((attachment) => vm.positiveInteger(
					attachment?.attachmentId ?? attachment?.id
				)).filter(Boolean),
			})),
		});

        const createPagerButton = (label, iconName, focusKey, page, disabled) => {
            const control = vm.button('', 'fotogenic-ai-progress-pager-button');
            control.setAttribute('aria-label', label);
            control.setAttribute('data-fa-focus-key', focusKey);
            control.disabled = Boolean(pending) || disabled;
            control.appendChild(icons.create(iconName, { size: 14 }));
            control.addEventListener('click', () => void invoke(focusKey.split(':').pop(), handlers.page, page));
            return control;
        };

        const renderCurrent = () => {
            if (!mount || !current || destroyed) return null;
			if (stopLayer?.parentElement) return current;
			if (stopLayer) closeStopDialog({ restore: false, immediate: true });
            restoreFocusKey = activeFocusKey()
                || restoreFocusKey
                || String(mount.getAttribute?.('data-fa-restore-focus-key') || '');
			const nextPresentationSignature = presentationSignature();
			if (nextPresentationSignature === lastPresentationSignature) {
				restoreFocus();
				return current;
			}
            renderControls();
            const content = vm.element('div', 'fotogenic-ai-progress-bulk-content');
            if (current.statusReason === 'authority_changed') {
                const warning = vm.element('div', 'fotogenic-ai-progress-warning');
                warning.setAttribute('role', 'alert');
                warning.append(
                    icons.create('warning', { weight: 'fill', size: 18 }),
                    vm.element('span', '', __( 'The accepted request authority changed. Review this exact saved request before any pending billable item can start.', 'fotogenic-ai' ))
                );
                content.appendChild(warning);
            }
            if (current.error || actionError) {
                const error = vm.element('p', 'fotogenic-ai-progress-action-error', actionError || current.error);
                error.setAttribute('role', 'alert');
                content.appendChild(error);
            }
            const grid = vm.element('div', 'fotogenic-ai-progress-grid');
            grid.setAttribute('data-fa-render-key', 'bulk:grid');
            const ledger = vm.element('section', 'fotogenic-ai-progress-ledger');
            ledger.setAttribute('data-fa-render-key', 'bulk:ledger');
            const header = vm.element('header', 'fotogenic-ai-progress-command-header');
            const heading = vm.element('h2', '', __( 'Run items', 'fotogenic-ai' ));
            heading.id = 'fotogenic-ai-bulk-run-items-title';
            ledger.setAttribute('aria-labelledby', heading.id);
            const partialLoaded = current.items.length < current.totalItems;
            const itemCountCopy = current.sourceType === 'product'
                ? sprintf(_n( '%d product', '%d products', current.totalItems, 'fotogenic-ai' ), current.totalItems)
                : sprintf(_n( '%d item', '%d items', current.totalItems, 'fotogenic-ai' ), current.totalItems);
            header.append(
                heading,
                vm.element('span', 'fotogenic-ai-progress-run-count', itemCountCopy)
            );
            const columns = vm.element('div', 'fotogenic-ai-progress-columns');
            [__( 'Source', 'fotogenic-ai' ), __( 'Outputs', 'fotogenic-ai' ), __( 'Status', 'fotogenic-ai' )]
                .forEach((label) => columns.appendChild(vm.element('span', '', label)));
            columns.setAttribute('aria-hidden', 'true');
            const rows = vm.element('div', 'fotogenic-ai-progress-rows');
            rows.setAttribute('data-fa-render-key', 'bulk:rows');
            rows.id = 'fotogenic-ai-bulk-progress-rows';
            if (current.loading && !current.items.length) {
                const loading = vm.element('p', 'fotogenic-ai-progress-empty', __( 'Loading current run items…', 'fotogenic-ai' ));
                loading.setAttribute('role', 'status');
                rows.appendChild(loading);
            } else if (!current.items.length) {
                rows.appendChild(vm.element('p', 'fotogenic-ai-progress-empty', __( 'No exact run-item details are available for this accepted run.', 'fotogenic-ai' )));
            } else {
                const activeIndex = current.items.findIndex((item) => ACTIVE_ITEM_STATUSES.has(item.status));
                const startingIndex = activeIndex < 0 && ['starting', 'processing'].includes(current.status)
                    ? current.items.findIndex((item) => item.status === 'queued')
                    : -1;
                const visibleItems = current.items.map((item, index) => index === startingIndex
                    ? { ...item, presentationStatus: 'starting' }
                    : item);
                const currentIndex = activeIndex >= 0 ? activeIndex : startingIndex;
                visibleItems.forEach((item, index) => rows.appendChild(createQueueRow(item, index === currentIndex && currentIndex >= 0)));
            }
            const footer = vm.element('footer', 'fotogenic-ai-progress-ledger-footer');
            if ((current.page > 1 || current.hasNext) && typeof handlers.page === 'function') {
                const pager = vm.element('nav', 'fotogenic-ai-progress-pager');
                pager.setAttribute('aria-label', __( 'Bulk queue pages', 'fotogenic-ai' ));
                pager.append(
                    createPagerButton(__( 'Previous queue page', 'fotogenic-ai' ), 'arrow-left', 'bulk:previous', current.page - 1, current.page <= 1),
                    vm.element('span', '', sprintf( __( '%1$d / %2$d', 'fotogenic-ai' ), current.page, current.totalPages )),
                    createPagerButton(__( 'Next queue page', 'fotogenic-ai' ), 'arrow-right', 'bulk:next', current.page + 1, !current.hasNext)
                );
                footer.appendChild(pager);
            }
            footer.hidden = !footer.childElementCount;
            ledger.append(header, columns, rows, footer);
            grid.append(
                ledger,
                progress.createLiveRunCard({
                    status: current.status,
                    items: partialLoaded ? current.items.length : current.totalItems,
                    outputs: current.outputCounts.total,
                    saved: current.outputCounts.completed,
                    failed: current.outputCounts.failed,
					allResultsRemoved: current.allResultsRemoved,
                    loaded: partialLoaded,
                    pollIntervalSeconds: current.pollIntervalSeconds,
                    renderKey: 'bulk:live-run',
					deliveryMode: current.deliveryMode,
                })
            );
            content.appendChild(grid);
            const existingContent = mount.querySelector('.fotogenic-ai-progress-bulk-content');
            if (existingContent) progress.reconcileElement(existingContent, content);
            else mount.replaceChildren(content);
			lastPresentationSignature = nextPresentationSignature;
            restoreFocus();

            if (lastStatus !== current.status) {
                lastStatus = current.status;
                announce(sprintf( __( 'Bulk run %s.', 'fotogenic-ai' ), progress.statusLabel(current.status) ));
            }
            return current;
        };

        const render = (value, nextHandlers = {}) => {
            actionError = '';
            current = normalizeBulk(value);
            handlers = nextHandlers && typeof nextHandlers === 'object' ? nextHandlers : {};
            return renderCurrent();
        };

        return Object.freeze({
            setMount,
            render,
            getFilter: () => 'all',
            destroy() {
                destroyed = true;
                window.clearTimeout(stopCloseTimer);
                closeStopDialog({ restore: false, immediate: true });
                mount?.replaceChildren?.();
                mount = null;
                current = null;
                handlers = {};
				lastPresentationSignature = '';
            },
        });
    };

    Studio.bulk = Object.freeze({
        createBulkView,
        normalizeBulk,
        normalizeItem,
        normalizeOutputCounts,
        orderItems,
        itemActionKind,
    });
})();
