// Bulk operations for parts in set details page
class PartsBulkOperations {
    constructor(accordionId) {
        this.accordionId = accordionId;
        this.setupModal();
        this.setupEventListeners();
    }

    setupModal() {
        // Create Bootstrap modal if it doesn't exist
        if (!document.getElementById('partsConfirmModal')) {
            const modalHTML = `
                <div class="modal fade" id="partsConfirmModal" tabindex="-1" aria-labelledby="partsConfirmModalLabel" aria-hidden="true">
                    <div class="modal-dialog">
                        <div class="modal-content">
                            <div class="modal-header">
                                <h5 class="modal-title" id="partsConfirmModalLabel">Confirm Action</h5>
                                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                            </div>
                            <div class="modal-body">
                                <p id="partsConfirmModalMessage"></p>
                            </div>
                            <div class="modal-footer">
                                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
                                <button type="button" class="btn btn-primary" id="partsConfirmModalConfirm">Confirm</button>
                            </div>
                        </div>
                    </div>
                </div>
            `;
            document.body.insertAdjacentHTML('beforeend', modalHTML);
        }
    }

    setupEventListeners() {
        // Mark all as missing (only if missing parts are not hidden)
        const markAllMissingBtn = document.getElementById(`mark-all-missing-${this.accordionId}`);
        if (markAllMissingBtn) {
            markAllMissingBtn.addEventListener('click', (e) => {
                e.preventDefault();
                this.confirmAndExecute(
                    'Mark all parts as missing?',
                    'This will set the missing count to the maximum quantity for all parts in this section.',
                    () => this.markAllMissing()
                );
            });
        }

        // Clear all missing (only if missing parts are not hidden)
        const clearAllMissingBtn = document.getElementById(`clear-all-missing-${this.accordionId}`);
        if (clearAllMissingBtn) {
            clearAllMissingBtn.addEventListener('click', (e) => {
                e.preventDefault();
                this.confirmAndExecute(
                    'Clear all missing parts?',
                    'This will clear the missing field for all parts in this section.',
                    () => this.clearAllMissing()
                );
            });
        }

        // Check all checkboxes (only if checked parts are not hidden)
        const checkAllBtn = document.getElementById(`check-all-${this.accordionId}`);
        if (checkAllBtn) {
            checkAllBtn.addEventListener('click', (e) => {
                e.preventDefault();
                this.checkAll();
            });
        }

        // Uncheck all checkboxes (only if checked parts are not hidden)
        const uncheckAllBtn = document.getElementById(`uncheck-all-${this.accordionId}`);
        if (uncheckAllBtn) {
            uncheckAllBtn.addEventListener('click', (e) => {
                e.preventDefault();
                this.uncheckAll();
            });
        }
    }

    confirmAndExecute(title, message, callback) {
        const modal = document.getElementById('partsConfirmModal');
        const modalTitle = document.getElementById('partsConfirmModalLabel');
        const modalMessage = document.getElementById('partsConfirmModalMessage');
        const confirmBtn = document.getElementById('partsConfirmModalConfirm');

        // Set modal content
        modalTitle.textContent = title;
        modalMessage.textContent = message;

        // Remove any existing event listeners and add new one
        const newConfirmBtn = confirmBtn.cloneNode(true);
        confirmBtn.parentNode.replaceChild(newConfirmBtn, confirmBtn);

        newConfirmBtn.addEventListener('click', () => {
            const modalInstance = bootstrap.Modal.getInstance(modal);
            modalInstance.hide();
            callback();
        });

        // Show modal
        const modalInstance = new bootstrap.Modal(modal);
        modalInstance.show();
    }

    // Parses BrickChanger's per-row "missing" URL to recover the pieces
    // needed to build a bulk request: the leading path prefix (for
    // subpath deployments), the set id, and the part's identity
    // (figure/part/color/spare). Returns null if the URL doesn't match.
    //
    // Matches URLs generated by url_for('set.problem_part', ...), e.g.
    // /sets/<id>/parts/<part>/<color>/<spare>/missing
    // /sets/<id>/minifigures/<figure>/parts/<part>/<color>/<spare>/missing
    static MISSING_URL_PATTERN = /^(.*?)\/sets\/([^/]+)\/(?:minifigures\/([^/]+)\/)?parts\/([^/]+)\/([^/]+)\/([^/]+)\/missing$/;

    // Send one bulk request updating every part's missing count in a
    // single call, instead of one fetch per row. Reloads the page once
    // the save is confirmed; shows an alert and does NOT reload on
    // failure, so a failed save is never silently discarded.
    _bulkUpdateMissing(items, urlPrefix, setId, actionLabel) {
        if (!items.length || !setId) return;

        fetch(`${urlPrefix}/sets/${setId}/parts/bulk/missing`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({ items }),
        })
            .then(response => {
                if (!response.ok) {
                    throw new Error(`Response status: ${response.status} (${response.statusText})`);
                }
                return response.json();
            })
            .then(json => {
                // The app's error handler returns HTTP 200 with an "error"
                // key for validation/application errors, not a 4xx status.
                if (json && 'error' in json) {
                    throw new Error(json.error);
                }

                // Only refresh once the save is confirmed, so all derived
                // totals (missing counts, etc.) reflect the new state.
                window.location.reload();
            })
            .catch(error => {
                console.error(`Bulk ${actionLabel} failed:`, error);
                alert(`Failed to save "${actionLabel}": ${error.message}`);
            });
    }

    // Walks the rows of this accordion, calling collect(missingInput,
    // quantityCell) for each visible row that has both a quantity cell
    // and a "missing" input. collect should return the desired new value
    // (a number) to set, or null/undefined to skip that row.
    _collectMissingItems(collect) {
        const accordionElement = document.getElementById(this.accordionId);
        if (!accordionElement) return { items: [], urlPrefix: '', setId: null };

        const rows = accordionElement.querySelectorAll('tbody tr');
        const items = [];
        let setId = null;
        let urlPrefix = '';

        rows.forEach(row => {
            // Skip rows hidden by an active header filter
            if (row.classList.contains('parts-filtered-out')) return;

            // Find the quantity cell (usually 4th column)
            const quantityCell = row.cells[3]; // Index 3 for quantity column
            const missingInput = row.querySelector('input[id*="-missing-"]');

            if (!quantityCell || !missingInput) return;

            const newValue = collect(missingInput, quantityCell);

            if (newValue === null || newValue === undefined) return;

            // Pull (id, figure, part, color, spare) straight out of the
            // per-row URL that BrickChanger already uses, so we don't need
            // any new data attributes in the template.
            const match = (missingInput.dataset.changerUrl || '').match(
                PartsBulkOperations.MISSING_URL_PATTERN
            );

            if (!match) {
                console.warn('Could not parse changer URL for a row, skipping it', missingInput);
                return;
            }

            const [, prefix, id, figure, part, color, spare] = match;
            setId = id;
            urlPrefix = prefix;

            // Reflect the new value in the UI immediately
            missingInput.value = newValue.toString();

            items.push({
                figure: figure || null,
                part: part,
                color: parseInt(color, 10),
                spare: parseInt(spare, 10),
                value: newValue,
            });
        });

        return { items, urlPrefix, setId };
    }

    markAllMissing() {
        const { items, urlPrefix, setId } = this._collectMissingItems((missingInput, quantityCell) => {
            const quantityText = quantityCell.textContent.trim();
            const quantity = parseInt(quantityText) || 1; // Default to 1 if can't parse

            if (missingInput.value === quantity.toString()) return null;

            return quantity;
        });

        this._bulkUpdateMissing(items, urlPrefix, setId, 'mark all missing');
    }

    clearAllMissing() {
        const { items, urlPrefix, setId } = this._collectMissingItems((missingInput) => {
            if (missingInput.value === '' || missingInput.value === '0') return null;

            return 0;
        });

        this._bulkUpdateMissing(items, urlPrefix, setId, 'clear all missing');
    }

    checkAll() {
        const accordionElement = document.getElementById(this.accordionId);
        if (!accordionElement) return;

        const checkboxes = accordionElement.querySelectorAll('input[id*="-checked-"][type="checkbox"]');
        checkboxes.forEach(checkbox => {
            if (checkbox.closest('tr')?.classList.contains('parts-filtered-out')) return;
            if (!checkbox.checked) {
                checkbox.checked = true;
                // Trigger change event to activate BrickChanger
                checkbox.dispatchEvent(new Event('change', { bubbles: true }));
            }
        });
    }

    uncheckAll() {
        const accordionElement = document.getElementById(this.accordionId);
        if (!accordionElement) return;

        const checkboxes = accordionElement.querySelectorAll('input[id*="-checked-"][type="checkbox"]');
        checkboxes.forEach(checkbox => {
            if (checkbox.closest('tr')?.classList.contains('parts-filtered-out')) return;
            if (checkbox.checked) {
                checkbox.checked = false;
                // Trigger change event to activate BrickChanger
                checkbox.dispatchEvent(new Event('change', { bubbles: true }));
            }
        });
    }
}

// Initialize bulk operations for all part accordions when DOM is ready
document.addEventListener('DOMContentLoaded', () => {
    // Find all hamburger menus and initialize bulk operations
    const hamburgerMenus = document.querySelectorAll('button[id^="hamburger-"]');
    hamburgerMenus.forEach(button => {
        const accordionId = button.id.replace('hamburger-', '');
        new PartsBulkOperations(accordionId);
    });
});