window.nexdirectoryUserManagementPage = function(seedUsers, initialSearch, actionUrl) {
    const users = Array.isArray(seedUsers) ? seedUsers.map(function(user) {
        const row = Object.assign({}, user || {});
        row.events = Array.isArray(row.events) ? row.events : [];
        if (!row.selectedEventId && row.events.length > 0) {
            row.selectedEventId = row.events[0].id;
        }
        row.eventSubject = String(row.eventSubject || '');
        row.eventMessage = String(row.eventMessage || '');
        return row;
    }) : [];

    return {
        users: users,
        searchQuery: String(initialSearch || ''),
        actionUrl: String(actionUrl || ''),
        currentPage: 1,
        itemsPerPage: 20,
        toolsOpen: {},
        noteModal: {
            open: false,
            user: null
        },
        noteModalDraft: '',
        toast: { show: false, message: '', type: 'info', timeout: null },

        init() {
            this.$watch('searchQuery', () => {
                this.currentPage = 1;
            });
        },

        async postAction(fields) {
            if (!this.actionUrl) {
                throw new Error('Action endpoint is missing.');
            }
            const params = new URLSearchParams();
            params.append('nexdirectory_ajax', '1');
            params.append('redirect_to', window.location.href);

            (fields || []).forEach(function(field) {
                if (!field || typeof field.name !== 'string') {
                    return;
                }
                const rawValue = field.value;
                if (rawValue === null || rawValue === undefined) {
                    return;
                }
                params.append(field.name, String(rawValue));
            });

            const response = await fetch(this.actionUrl, {
                method: 'POST',
                credentials: 'same-origin',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
                    'X-Requested-With': 'XMLHttpRequest'
                },
                body: params.toString()
            });
            const text = await response.text();
            let payload = null;
            try {
                payload = text ? JSON.parse(text) : null;
            } catch (error) {
                payload = null;
            }

            if (!payload || payload.success !== true) {
                const message = payload && payload.data && payload.data.message
                    ? String(payload.data.message)
                    : 'Request failed.';
                throw new Error(message);
            }
            return payload.data || {};
        },

        updateUserEventCounters(user) {
            if (!user || !Array.isArray(user.events)) {
                return;
            }
            let published = 0;
            let pending = 0;
            let draft = 0;
            user.events.forEach(function(eventItem) {
                const status = String(eventItem && eventItem.status ? eventItem.status : '');
                if (status === 'publish') {
                    published += 1;
                } else if (status === 'pending') {
                    pending += 1;
                } else if (status === 'draft') {
                    draft += 1;
                }
            });
            user.eventsTotal = user.events.length;
            user.publishedEvents = published;
            user.pendingEvents = pending;
            user.draftEvents = draft;
        },

        updateUserRole(user, nextRole, selectEl) {
            if (!user || !user.roleMutable) {
                return;
            }
            const role = String(nextRole || '');
            if (role !== 'subscriber' && role !== 'event_submitter') {
                if (selectEl) {
                    selectEl.value = String(user.role || 'subscriber');
                }
                return;
            }
            const previousRole = String(user.role || 'subscriber');
            if (role === previousRole) {
                return;
            }
            this.postAction([
                { name: 'action', value: 'nexdirectory_manage_user_role' },
                { name: 'user_id', value: user.id },
                { name: 'role', value: role },
                { name: 'nexdirectory_manage_user_nonce', value: user.nonces ? user.nonces.role : '' }
            ]).then((data) => {
                user.role = String(data.role || role);
                if (data.role_label) {
                    user.roleLabel = String(data.role_label);
                }
                this.showToast(String(data.message || 'User role updated.'), 'success');
            }).catch((error) => {
                user.role = previousRole;
                if (selectEl) {
                    selectEl.value = previousRole;
                }
                this.showToast(String(error && error.message ? error.message : 'Could not update role.'), 'error');
            });
        },

        toggleVerified(user) {
            if (!user || user.isAdmin) {
                return;
            }
            const nextVerified = !Boolean(user.verified);
            this.postAction([
                { name: 'action', value: 'nexdirectory_toggle_verified' },
                { name: 'user_id', value: user.id },
                { name: 'verified', value: nextVerified ? '1' : '0' },
                { name: 'nexdirectory_toggle_verified_nonce', value: user.nonces ? user.nonces.verified : '' }
            ]).then((data) => {
                user.verified = Boolean(data.verified);
                this.showToast(String(data.message || 'Verification updated.'), 'success');
            }).catch((error) => {
                this.showToast(String(error && error.message ? error.message : 'Could not update verification.'), 'error');
            });
        },

        updateUserTrust(user, nextState, selectEl) {
            if (!user || user.isAdmin) {
                return;
            }
            const requested = String(nextState || '');
            if (requested !== 'trusted' && requested !== 'require_approval') {
                if (selectEl) {
                    selectEl.value = String(user.trusted || 'require_approval');
                }
                return;
            }
            const previousState = String(user.trusted || 'require_approval');
            if (requested === previousState) {
                return;
            }
            this.postAction([
                { name: 'action', value: 'nexdirectory_toggle_user_edit_trust' },
                { name: 'user_id', value: user.id },
                { name: 'trusted', value: requested },
                { name: 'nexdirectory_toggle_user_edit_trust_nonce', value: user.nonces ? user.nonces.trust : '' }
            ]).then((data) => {
                user.trusted = String(data.trusted || requested);
                this.showToast(String(data.message || 'Trust settings updated.'), 'success');
            }).catch((error) => {
                user.trusted = previousState;
                if (selectEl) {
                    selectEl.value = previousState;
                }
                this.showToast(String(error && error.message ? error.message : 'Could not update trust settings.'), 'error');
            });
        },

        manageUserEvent(user, intent) {
            if (!user || !user.id || !user.selectedEventId) {
                this.showToast('Select an event first.', 'error');
                return;
            }
            const selectedId = Number(user.selectedEventId || 0);
            if (selectedId <= 0) {
                this.showToast('Select a valid event.', 'error');
                return;
            }

            this.postAction([
                { name: 'action', value: 'nexdirectory_manage_user_event' },
                { name: 'user_id', value: user.id },
                { name: 'event_id', value: selectedId },
                { name: 'intent', value: String(intent || '') },
                { name: 'admin_subject', value: String(user.eventSubject || '') },
                { name: 'admin_message', value: String(user.eventMessage || '') },
                { name: 'nexdirectory_manage_user_event_nonce', value: user.nonces ? user.nonces.event : '' }
            ]).then((data) => {
                if (data.intent === 'open_event' && data.open_url) {
                    window.open(String(data.open_url), '_blank', 'noopener,noreferrer');
                }
                if ((data.intent === 'publish_event' || data.intent === 'unpublish_event') && data.post_id) {
                    const eventId = Number(data.post_id || 0);
                    user.events.forEach(function(eventItem) {
                        if (Number(eventItem.id || 0) === eventId) {
                            eventItem.status = String(data.new_status || eventItem.status || '');
                            eventItem.status_label = String(data.status_label || eventItem.status_label || '');
                        }
                    });
                    this.updateUserEventCounters(user);
                }
                this.showToast(String(data.message || 'Event updated.'), 'success');
            }).catch((error) => {
                this.showToast(String(error && error.message ? error.message : 'Could not update event.'), 'error');
            });
        },

        get filteredUsers() {
            const query = String(this.searchQuery || '').trim().toLowerCase();
            if (query === '') {
                return this.users;
            }
            return this.users.filter((user) => {
                const name = String(user.name || '').toLowerCase();
                const email = String(user.email || '').toLowerCase();
                return name.indexOf(query) !== -1 || email.indexOf(query) !== -1;
            });
        },

        get paginatedUsers() {
            const start = (this.currentPage - 1) * this.itemsPerPage;
            return this.filteredUsers.slice(start, start + this.itemsPerPage);
        },

        get paginationStart() {
            return this.filteredUsers.length === 0 ? 0 : ((this.currentPage - 1) * this.itemsPerPage) + 1;
        },

        get paginationEnd() {
            return Math.min(this.currentPage * this.itemsPerPage, this.filteredUsers.length);
        },

        get totalPages() {
            return Math.max(1, Math.ceil(this.filteredUsers.length / this.itemsPerPage));
        },

        get verifiedCount() {
            return this.filteredUsers.filter((user) => !!user.verified).length;
        },

        get submitterCount() {
            return this.filteredUsers.filter((user) => String(user.role || '') === 'event_submitter').length;
        },

        get trustedCount() {
            return this.filteredUsers.filter((user) => String(user.trusted || '') === 'trusted').length;
        },

        nextPage() {
            if (this.currentPage < this.totalPages) {
                this.currentPage += 1;
            }
        },

        prevPage() {
            if (this.currentPage > 1) {
                this.currentPage -= 1;
            }
        },

        toggleTools(userId) {
            const key = String(userId || '');
            if (!key) {
                return;
            }
            this.toolsOpen[key] = !this.toolsOpen[key];
        },

        isToolsOpen(userId) {
            return !!this.toolsOpen[String(userId || '')];
        },

        loginAs(user) {
            if (!user || !user.urls || !user.urls.profile) {
                return;
            }
            this.showToast('Opening profile for ' + String(user.name || 'user') + '.', 'info');
            window.location.href = String(user.urls.profile);
        },

        openNotes(user) {
            if (!user || !user.id) {
                return;
            }
            this.noteModal.user = user;
            this.noteModalDraft = String(user.notes || '');
            this.noteModal.open = true;
            document.body.style.overflow = 'hidden';
        },

        closeNotes() {
            this.noteModal.open = false;
            this.noteModal.user = null;
            this.noteModalDraft = '';
            document.body.style.overflow = '';
        },

        saveNotes() {
            if (!this.noteModal.user || !this.noteModal.user.id) {
                return;
            }
            const modalUser = this.noteModal.user;
            const noteValue = String(this.noteModalDraft || '');
            this.postAction([
                { name: 'action', value: 'nexdirectory_manage_user_note' },
                { name: 'user_id', value: modalUser.id },
                { name: 'admin_note', value: noteValue },
                { name: 'nexdirectory_manage_user_note_nonce', value: modalUser.nonces ? modalUser.nonces.note : '' }
            ]).then((data) => {
                modalUser.notes = String(data.admin_note !== undefined ? data.admin_note : noteValue);
                this.closeNotes();
                this.showToast(String(data.message || 'Admin note saved.'), 'success');
            }).catch((error) => {
                this.showToast(String(error && error.message ? error.message : 'Could not save note.'), 'error');
            });
        },

        showToast(message, type) {
            this.toast.message = String(message || '');
            this.toast.type = String(type || 'info');
            this.toast.show = true;
            if (this.toast.timeout) {
                clearTimeout(this.toast.timeout);
            }
            this.toast.timeout = setTimeout(() => {
                this.toast.show = false;
            }, 2600);
        },

        exportCsv() {
            const headers = ['ID', 'Name', 'Email', 'Role', 'Verified', 'Trusted', 'Events', 'Pending', 'Last Active'];
            const csvCell = (value) => {
                let text = String(value === null || value === undefined ? '' : value);
                if (/^[\u0000-\u0020\uFEFF]*[=+\-@]/.test(text)) {
                    text = "'" + text;
                }
                return '"' + text.replace(/"/g, '""') + '"';
            };
            const rows = [headers.map(csvCell).join(',')];
            this.filteredUsers.forEach((user) => {
                rows.push([
                    String(user.id || ''),
                    String(user.name || ''),
                    String(user.email || ''),
                    String(user.roleLabel || user.role || ''),
                    user.verified ? 'Yes' : 'No',
                    String(user.trusted || '') === 'trusted' ? 'Trusted' : 'Require Approval',
                    String(user.eventsTotal || 0),
                    String(user.pendingEvents || 0),
                    String(user.lastActive || '')
                ].map(csvCell).join(','));
            });

            const csv = rows.join('\n');
            const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
            const link = document.createElement('a');
            const url = URL.createObjectURL(blob);
            link.setAttribute('href', url);
            link.setAttribute('download', 'users_' + new Date().toISOString().slice(0, 10) + '.csv');
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            URL.revokeObjectURL(url);
            this.showToast('CSV exported.', 'success');
        }
    };
};
