/**
 * Staff screen (Yatoon > Staff).
 *
 * Lifted out of admin/views/staff.php, where it was ~800 lines of inline
 * <script>. Inline admin JS is never cached between page loads, never
 * minified, and invisible to `node --check` and the asset gates -- the same
 * blind spot that let a corrupted stylesheet and a boot-time fatal ship.
 *
 * Every value that used to be interpolated by PHP now arrives on
 * yatoonStaffData (see YATOON_Admin::enqueue_admin_scripts).
 */
/* global jQuery, ajaxurl, wp, yatoonStaffData */
jQuery(document).ready(function($) {
    let currentStaffId = null;
    const staffServicesNonce = yatoonStaffData.staffServicesNonce;
    const adminNonce = yatoonStaffData.adminNonce;

    function showStaffServicesNotice(message, isError) {
        const styles = isError
            ? { background: '#fef2f2', border: '1px solid #fecaca', color: '#991b1b' }
            : { background: '#ecfdf5', border: '1px solid #a7f3d0', color: '#065f46' };

        const $notice = $('#sbs-rebuild-result');
        $notice.stop(true, true).text(message).css(styles).show();
    }

    function updateSelectedStaffState() {
        const total = $('.sbs-staff-row-checkbox').length;
        const checked = $('.sbs-staff-row-checkbox:checked').length;
        $('#sbs-delete-selected-staff').prop('disabled', checked === 0);
        $('#sbs-select-all-staff')
            .prop('checked', total > 0 && checked === total)
            .prop('indeterminate', checked > 0 && checked < total);
        $('.sbs-staff-row-checkbox').each(function() {
            $(this).closest('tr').toggleClass('is-selected', $(this).is(':checked'));
        });
    }

    $('#sbs-select-all-staff').on('change', function() {
        $('.sbs-staff-row-checkbox').prop('checked', $(this).is(':checked'));
        updateSelectedStaffState();
    });

    $(document).on('change', '.sbs-staff-row-checkbox', function() {
        updateSelectedStaffState();
        // See bookings.php: reading offsetHeight does not reliably force
        // Chromium/Edge to repaint this checkbox's own check-mark. Cloning
        // the element and swapping it in does.
        const cb = this;
        const isChecked = cb.checked;
        const freshCb = cb.cloneNode(true);
        freshCb.checked = isChecked;
        cb.parentNode.replaceChild(freshCb, cb);
    });

    function applyStaffFilters() {
        const q = ($('#sbs-staff-search').val() || '').toLowerCase().trim();
        const status = ($('#sbs-staff-status-filter').val() || '').toLowerCase();
        const online = ($('#sbs-staff-online-filter').val() || '').toLowerCase();

        $('#sbs-staff-table tbody tr').each(function() {
            const $row = $(this);
            const matchesText = !q || String($row.data('search') || '').indexOf(q) !== -1;
            const matchesStatus = !status || String($row.data('status') || '') === status;
            const matchesOnline = !online || String($row.data('online') || '') === online;
            $row.toggle(matchesText && matchesStatus && matchesOnline);
        });
    }

    $('#sbs-staff-search, #sbs-staff-status-filter, #sbs-staff-online-filter').on('input change', applyStaffFilters);
    $('#sbs-staff-clear-filters').on('click', function() {
        $('#sbs-staff-search').val('');
        $('#sbs-staff-status-filter').val('');
        $('#sbs-staff-online-filter').val('');
        applyStaffFilters();
    });

    $('#sbs-delete-selected-staff').on('click', function() {
        const ids = $('.sbs-staff-row-checkbox:checked').map(function() {
            return parseInt($(this).val(), 10);
        }).get().filter(Boolean);

        if (!ids.length) {
            return;
        }

        if (!window.confirm('Delete selected staff members? This cannot be undone.')) {
            return;
        }

        const $btn = $(this).prop('disabled', true).text('Deleting...');

        $.post(ajaxurl, {
            action: 'yatoon_delete_staff',
            nonce: adminNonce,
            staff_ids: ids
        }, function(resp) {
            if (resp.success) {
                ids.forEach(function(id) {
                    $('#sbs-staff-row-' + id).remove();
                });
                updateSelectedStaffState();
                showStaffServicesNotice(resp?.data?.message || 'Staff members deleted.', false);
                if (!$('.sbs-staff-row-checkbox').length) {
                    location.reload();
                }
            } else {
                showStaffServicesNotice(resp?.data?.message || 'Failed to delete selected staff members.', true);
            }
        }).fail(function() {
            showStaffServicesNotice('Could not delete selected staff members. Please try again.', true);
        }).always(function() {
            $btn.text('Delete Selected');
            updateSelectedStaffState();
        });
    });

    // Rebuild Service Assignments button
    $('#sbs-rebuild-staff-services').on('click', function() {
        const $btn = $(this);
        const $notice = $('#sbs-rebuild-result');
        $btn.prop('disabled', true).text('Rebuilding...');
        $notice.hide();

        $.post(ajaxurl, {
            action: 'yatoon_rebuild_staff_services',
            nonce: adminNonce
        }, function(resp) {
            if (resp.success) {
                showStaffServicesNotice('OK ' + (resp.data.message || 'Service assignments rebuilt successfully!'), false);
            } else {
                showStaffServicesNotice('Error: ' + (resp.data && resp.data.message ? resp.data.message : 'Rebuild failed'), true);
            }
        }).fail(function() {
                showStaffServicesNotice('Error: ' + (resp.data && resp.data.message ? resp.data.message : 'Rebuild failed'), true);
        }).always(function() {
            $btn.prop('disabled', false).text('Rebuild Service Assignments');
        });
    });

    let staffImageFrame = null;

    $('<style>')
        .text('.sbs-staff-avatar-btn{border:0;background:transparent;padding:0;margin:0;cursor:pointer;border-radius:50%;display:inline-flex;}'
            + '.sbs-staff-avatar-btn:hover{box-shadow:0 0 0 3px #bfdbfe;}'
            + '.sbs-staff-name-link{font-weight:700;text-decoration:none;}'
            + '.sbs-staff-name-link:hover{text-decoration:underline;}'
            + '#sbs-staff-modal .sbs-staff-modal-card{box-sizing:border-box;}'
            + '#sbs-staff-modal .form-table{width:100%;table-layout:fixed;}'
            + '#sbs-staff-modal .form-table th{width:118px;padding-right:18px;}'
            + '#sbs-staff-modal .form-table td{min-width:0;}'
            + '#sbs-staff-modal input.regular-text,#sbs-staff-modal textarea.large-text{width:100%;max-width:100%;box-sizing:border-box;}'
            + '.sbs-permission-list{display:grid;gap:8px;max-width:420px;}'
            + '.sbs-permission-list label{display:flex;align-items:center;gap:8px;font-weight:500;color:#1f2937;}'
            + '.sbs-staff-photo-preview{margin:0 0 10px;}'
            + '.sbs-timeoff-editor{display:flex;flex-direction:column;gap:10px;margin-bottom:10px;}'
            + '.sbs-timeoff-row{display:grid;grid-template-columns:minmax(160px,1fr) minmax(112px,.7fr) minmax(112px,.7fr) minmax(170px,1fr);gap:8px;align-items:center;padding:10px;border:1px solid #e5e7eb;border-radius:10px;background:#f9fafb;max-width:100%;box-sizing:border-box;}'
            + '.sbs-timeoff-row input[type="date"],.sbs-timeoff-row input[type="time"],.sbs-timeoff-row input[type="text"]{width:100%;min-height:36px;}'
            + '.sbs-timeoff-row label{white-space:nowrap;}'
            + '.sbs-timeoff-row .sbs-remove-timeoff-row{justify-self:start;}'
            + '.sbs-timeoff-row.is-all-day .sbs-timeoff-time{opacity:.45;pointer-events:none;}'
            + '@media(min-width:783px){.sbs-timeoff-row label,.sbs-timeoff-row .sbs-remove-timeoff-row{grid-column:auto;}}'
            + '@media(max-width:1040px){.sbs-timeoff-row{grid-template-columns:1fr 1fr;}.sbs-timeoff-row .sbs-timeoff-note{grid-column:1/-1;}}'
            + '@media(max-width:782px){#sbs-staff-modal{padding:10px !important;}#sbs-staff-modal .form-table,#sbs-staff-modal .form-table tbody,#sbs-staff-modal .form-table tr,#sbs-staff-modal .form-table th,#sbs-staff-modal .form-table td{display:block;width:100%;box-sizing:border-box;}#sbs-staff-modal .form-table th{padding:10px 0 6px;}.sbs-timeoff-row{grid-template-columns:1fr;}.sbs-timeoff-row .sbs-timeoff-note{grid-column:auto;}}')
        .appendTo('head');

    function setStaffImage(url) {
        url = url || '';
        $('#sbs-staff-image-url').val(url);
        if (url) {
            $('#sbs-staff-image-preview').show().find('img').attr('src', url).attr('alt', $('#sbs-staff-name').val() || 'Staff photo');
            $('#sbs-staff-image-remove').show();
        } else {
            $('#sbs-staff-image-preview').hide().find('img').attr('src', '').attr('alt', '');
            $('#sbs-staff-image-remove').hide();
        }
    }

    function addTimeOffRow(block) {
        block = block || {};
        const allDay = !!block.allDay;
        const $row = $('<div class="sbs-timeoff-row">\
            <input type="date" class="sbs-timeoff-date" aria-label="Blocked date">\
            <input type="time" class="sbs-timeoff-start sbs-timeoff-time" aria-label="Start time">\
            <input type="time" class="sbs-timeoff-end sbs-timeoff-time" aria-label="End time">\
            <input type="text" class="sbs-timeoff-note" aria-label="Note" placeholder="Note, e.g. Vacation">\
            <label><input type="checkbox" class="sbs-timeoff-all-day"> All day</label>\
            <button type="button" class="button-link-delete sbs-remove-timeoff-row">Remove</button>\
        </div>');
        $row.find('.sbs-timeoff-date').val(block.date || '');
        $row.find('.sbs-timeoff-start').val(block.start || '');
        $row.find('.sbs-timeoff-end').val(block.end || '');
        $row.find('.sbs-timeoff-note').val(block.note || '');
        $row.find('.sbs-timeoff-all-day').prop('checked', allDay);
        $row.toggleClass('is-all-day', allDay);
        $('#sbs-staff-timeoff-rows').append($row);
    }

    function parseTimeOffRules(raw) {
        const blocks = [];
        (raw || '').split(/\r?\n/).forEach(function(line) {
            line = $.trim(line);
            if (!line) { return; }
            const parts = line.split('|');
            const first = parts[0] || '';
            const second = parts[1] || '';
            const note = parts.slice(2).join('|') || '';
            const date = first.substring(0, 10);
            if (second === 'all_day') {
                blocks.push({ date: date, allDay: true, note: note });
                return;
            }
            blocks.push({
                date: date,
                start: first.length > 10 ? first.substring(11, 16) : '',
                end: second.length > 10 ? second.substring(11, 16) : '',
                note: note
            });
        });
        return blocks;
    }

    function renderTimeOffEditor(raw) {
        const blocks = parseTimeOffRules(raw);
        $('#sbs-staff-timeoff-rows').empty();
        if (!blocks.length) {
            addTimeOffRow();
            return;
        }
        blocks.forEach(addTimeOffRow);
    }

    function serializeTimeOffEditor() {
        const lines = [];
        $('#sbs-staff-timeoff-rows .sbs-timeoff-row').each(function() {
            const $row = $(this);
            const date = $row.find('.sbs-timeoff-date').val();
            const note = $row.find('.sbs-timeoff-note').val().trim();
            const allDay = $row.find('.sbs-timeoff-all-day').is(':checked');
            if (!date) { return; }
            if (allDay) {
                lines.push(date + '|all_day|' + note);
                return;
            }
            const start = $row.find('.sbs-timeoff-start').val();
            const end = $row.find('.sbs-timeoff-end').val();
            if (!start || !end) { return; }
            lines.push(date + ' ' + start + '|' + date + ' ' + end + '|' + note);
        });
        return lines.join('\n');
    }

    function setPortalPermissions(raw) {
        const selected = String(raw || 'view_schedule').split(',').map(v => v.trim()).filter(Boolean);
        $('.sbs-staff-permission').each(function() {
            const value = $(this).val();
            $(this).prop('checked', value === 'view_schedule' || selected.includes(value));
        });
    }

    function serializePortalPermissions() {
        const values = ['view_schedule'];
        $('.sbs-staff-permission:checked').each(function() {
            const value = $(this).val();
            if (value && !values.includes(value)) {
                values.push(value);
            }
        });
        return values.join(',');
    }

    const portalRolePermissions = {
        staff: ['view_schedule', 'update_status', 'view_clients', 'send_messages', 'request_time_off'],
        manager: ['view_schedule', 'update_status', 'view_clients', 'send_messages', 'request_time_off', 'view_all_schedules', 'create_booking', 'edit_booking', 'cancel_booking', 'manage_clients', 'checkout', 'approve_time_off'],
        owner: ['view_schedule', 'view_all_schedules', 'update_status', 'create_booking', 'edit_booking', 'cancel_booking', 'view_clients', 'manage_clients', 'send_messages', 'checkout', 'request_time_off', 'approve_time_off']
    };

    function applyPortalRole(role) {
        const selected = portalRolePermissions[role] || portalRolePermissions.staff;
        $('.sbs-staff-permission').each(function() {
            $(this).prop('checked', selected.includes($(this).val()));
        });
    }

    // -- Portal sign-in section inside the Edit Staff Member editor --------
    let portalAccessStaff = { id: 0, name: '', hasPin: false };

    function renderPinState() {
        const $state = $('#sbs-staff-pin-state');
        const $set = $('#sbs-staff-modal-set-pin');
        const $remove = $('#sbs-staff-modal-remove-pin');
        if (!portalAccessStaff.id) {
            $state.removeClass('is-set').text('');
            $set.prop('disabled', true);
            $remove.hide();
            $('#sbs-staff-pin-hint').show();
            return;
        }
        $('#sbs-staff-pin-hint').hide();
        $set.prop('disabled', false).text(portalAccessStaff.hasPin ? 'Change PIN' : 'Set PIN');
        $remove.toggle(portalAccessStaff.hasPin);
        $state.toggleClass('is-set', portalAccessStaff.hasPin)
              .text(portalAccessStaff.hasPin ? 'PIN is set' : 'No PIN yet - this employee cannot sign in with a PIN');
    }

    function applyPortalAccess(id, name, email, d) {
        portalAccessStaff = {
            id: parseInt(id, 10) || 0,
            name: name || '',
            hasPin: String(d.hasPin || '0') === '1'
        };
        $('#sbs-staff-allow-google').prop('checked', String(d.googleLogin || '0') === '1');
        $('#sbs-staff-allow-otp').prop('checked', String(d.otpLogin || '0') === '1');

        // A one-time code needs somewhere to go.
        const reachable = !!(email || '').trim() || !!String(d.phone || '').trim();
        $('#sbs-staff-allow-otp').prop('disabled', !reachable);
        $('#sbs-staff-otp-hint').text(reachable
            ? 'Sends a one-time code to this employee\u2019s email address or phone number.'
            : 'Add an email address for this employee first.');

        $('#sbs-pin-length-warning').hide();
        renderPinState();
    }

    $('#sbs-staff-modal-set-pin').on('click', function() {
        if (!portalAccessStaff.id || !window.yatoonStaffPin) { return; }
        window.yatoonStaffPin.open(portalAccessStaff.id, portalAccessStaff.name, function(hasPin) {
            portalAccessStaff.hasPin = hasPin;
            renderPinState();
            $('#sbs-staff-save-status').html('<span style="color:#10B981;font-weight:600;">PIN saved.</span>');
        });
    });

    $('#sbs-staff-modal-remove-pin').on('click', function() {
        if (!portalAccessStaff.id || !window.yatoonStaffPin) { return; }
        if (!window.confirm('Remove this PIN? This employee will not be able to sign in with a PIN until a new one is set.')) { return; }
        const $btn = $(this).prop('disabled', true);
        window.yatoonStaffPin.save(portalAccessStaff.id, '', function(resp) {
            $btn.prop('disabled', false);
            if (resp && resp.success) {
                portalAccessStaff.hasPin = false;
                renderPinState();
                $('#sbs-staff-save-status').html('<span style="color:#10B981;font-weight:600;">PIN removed.</span>');
            } else {
                $('#sbs-staff-save-status').html('<span style="color:#dc2626;">' + ((resp && resp.data && resp.data.message) || 'Could not remove the PIN.') + '</span>');
            }
        }).fail(function() {
            $btn.prop('disabled', false);
            $('#sbs-staff-save-status').html('<span style="color:#dc2626;">Network error.</span>');
        });
    });

    // PIN length is salon-wide, so it saves the moment it changes rather than
    // riding along with this one employee's Save button.
    $('input[name="sbs-staff-pin-length"]').on('change', function() {
        const $radios = $('input[name="sbs-staff-pin-length"]');
        const length = parseInt($(this).val(), 10);
        const previous = length === 4 ? 6 : 4;
        if (!window.confirm('Change the PIN length to ' + length + ' digits for every employee? Existing PINs must be set again before those employees can sign in.')) {
            $radios.filter('[value="' + previous + '"]').prop('checked', true);
            return;
        }
        $radios.prop('disabled', true);
        $.post(ajaxurl, {
            action: 'yatoon_set_staff_pin_length',
            nonce: window.yatoonStaffPin ? window.yatoonStaffPin.nonce : '',
            pin_length: length
        }, function(resp) {
            $radios.prop('disabled', false);
            if (resp && resp.success) {
                $('#sbs-pin-length-warning').show();
                if (window.yatoonStaffPin) { window.yatoonStaffPin.applyLength(length); }
            } else {
                $radios.filter('[value="' + previous + '"]').prop('checked', true);
                $('#sbs-staff-save-status').html('<span style="color:#dc2626;">' + ((resp && resp.data && resp.data.message) || 'Could not change the PIN length.') + '</span>');
            }
        }).fail(function() {
            $radios.prop('disabled', false).filter('[value="' + previous + '"]').prop('checked', true);
            $('#sbs-staff-save-status').html('<span style="color:#dc2626;">Network error.</span>');
        });
    });

    function openStaffModal(id, name, email, bio, active, bookable, timeoff, imageUrl, permissions, calendarColor, role, sortOrder, access) {
        $('#sbs-staff-id').val(id || 0);
        $('#sbs-staff-name').val(name || '');
        $('#sbs-staff-email').val(email || '');
        $('#sbs-staff-bio').val(bio || '');
        $('#sbs-staff-sort-order').val(id ? Math.max(0, parseInt(sortOrder, 10) || 0) : '');
        setStaffImage(imageUrl || '');
        $('#sbs-staff-calendar-color').val(/^#[0-9a-f]{6}$/i.test(calendarColor || '') ? calendarColor : '#84cc16');
        $('#sbs-staff-active').prop('checked', parseInt(active, 10) !== 0);
        $('#sbs-staff-bookable').prop('checked', parseInt(bookable, 10) !== 0);
        $('#sbs-staff-portal-role').val(role || 'staff');
        if (id) {
            setPortalPermissions(permissions || 'view_schedule');
        } else {
            applyPortalRole(role || 'staff');
        }
        renderTimeOffEditor(timeoff || '');
        applyPortalAccess(id, name, email, access || {});
        $('#sbs-staff-modal-title').text(id ? 'Edit Staff Member' : 'Add Staff Member');
        $('#sbs-staff-save-status').empty();
        $('#sbs-staff-modal').fadeIn(150);
    }

    $('#sbs-add-staff-btn').on('click', function() {
        if ( $(this).prop('disabled') ) { return; }
        openStaffModal(0);
    });

    $(document).on('click', '.sbs-edit-staff-btn', function() {
        const d = $(this).data();
        openStaffModal(d.id, d.name, d.email, d.bio, d.active, d.bookable, d.timeoff, d.image, d.permissions, d.color, d.role, d.sortOrder, d);
    });

    $(document).on('click', '.sbs-staff-open-profile', function() {
        const $row = $(this).closest('tr');
        const d = $row.data();
        // The sign-in state lives on the row's Edit button, so read it from
        // there rather than duplicating four data attributes on the <tr>.
        const access = $row.find('.sbs-edit-staff-btn').first().data() || {};
        openStaffModal(d.id, d.name, d.email, d.bio, d.active, d.bookable, d.timeoff, d.image, d.permissions, d.color, d.role, d.sortOrder, access);
    });

    $('#sbs-staff-portal-role').on('change', function() {
        applyPortalRole($(this).val());
    });

    $('#sbs-staff-image-upload').on('click', function(e) {
        e.preventDefault();
        if (staffImageFrame) {
            staffImageFrame.open();
            return;
        }
        staffImageFrame = wp.media({
            title: 'Choose Staff Photo',
            button: { text: 'Use this photo' },
            library: { type: 'image' },
            multiple: false
        });
        staffImageFrame.on('select', function() {
            const attachment = staffImageFrame.state().get('selection').first().toJSON();
            const url = attachment.sizes && attachment.sizes.thumbnail ? attachment.sizes.thumbnail.url : attachment.url;
            setStaffImage(url);
        });
        staffImageFrame.open();
    });

    $('#sbs-staff-image-remove').on('click', function(e) {
        e.preventDefault();
        setStaffImage('');
    });

    $('#sbs-add-timeoff-row').on('click', function() {
        addTimeOffRow();
    });

    $(document).on('click', '.sbs-remove-timeoff-row', function() {
        $(this).closest('.sbs-timeoff-row').remove();
        if (!$('#sbs-staff-timeoff-rows .sbs-timeoff-row').length) {
            addTimeOffRow();
        }
    });

    $(document).on('change', '.sbs-timeoff-all-day', function() {
        $(this).closest('.sbs-timeoff-row').toggleClass('is-all-day', $(this).is(':checked'));
    });

    $('#sbs-staff-modal-close, #sbs-staff-modal-cancel').on('click', function() {
        $('#sbs-staff-modal').fadeOut(150);
    });

    $('#sbs-staff-modal').on('click', function(e) {
        if (e.target === this) {
            $('#sbs-staff-modal').fadeOut(150);
        }
    });

    $('#sbs-staff-modal-save').on('click', function() {
        const $btn = $(this).prop('disabled', true).text('Saving...');
        $.post(ajaxurl, {
            action: 'yatoon_save_staff',
            nonce: adminNonce,
            staff_id: $('#sbs-staff-id').val(),
            name: $('#sbs-staff-name').val().trim(),
            email: $('#sbs-staff-email').val().trim(),
            bio: $('#sbs-staff-bio').val().trim(),
            sort_order: $('#sbs-staff-sort-order').val(),
            image_url: $('#sbs-staff-image-url').val(),
            calendar_color: $('#sbs-staff-calendar-color').val(),
            is_active: $('#sbs-staff-active').is(':checked') ? 1 : 0,
            is_bookable: $('#sbs-staff-bookable').is(':checked') ? 1 : 0,
            portal_role: $('#sbs-staff-portal-role').val(),
            portal_permissions: serializePortalPermissions(),
            manages_login_methods: 1,
            allow_google_login: $('#sbs-staff-allow-google').is(':checked') ? 1 : 0,
            allow_otp_login: $('#sbs-staff-allow-otp').is(':checked') ? 1 : 0,
            time_off_rules: serializeTimeOffEditor()
        }, function(resp) {
            $btn.prop('disabled', false).text('Save');
            if (resp.success) {
                $('#sbs-staff-save-status').html('<span style="color:#10B981;font-weight:600;">Saved.</span>');
                setTimeout(function() { location.reload(); }, 600);
            } else {
                $('#sbs-staff-save-status').html('<span style="color:#dc2626;">' + (resp.data && resp.data.message ? resp.data.message : 'Error') + '</span>');
            }
        }).fail(function() {
            $btn.prop('disabled', false).text('Save');
            $('#sbs-staff-save-status').html('<span style="color:#dc2626;">Network error.</span>');
        });
    });

    $('#sbs-save-assignment-strategy').on('click', function() {
        const $btn = $(this).prop('disabled', true).text('Saving...');
        const $status = $('#sbs-assignment-strategy-status').text('');
        $.post(ajaxurl, {
            action: 'yatoon_save_staff_assignment_strategy',
            nonce: adminNonce,
            assignment_strategy: $('#sbs-any-staff-strategy').val()
        }, function(resp) {
            if (resp && resp.success) {
                $status.css('color', '#008a20').text('Saved.');
            } else {
                $status.css('color', '#b32d2e').text(resp && resp.data && resp.data.message ? resp.data.message : 'Could not save.');
            }
        }).fail(function() {
            $status.css('color', '#b32d2e').text('Network error.');
        }).always(function() {
            $btn.prop('disabled', false).text('Save assignment rule');
        });
    });

    $(document).on('click', '.sbs-delete-staff-btn', function() {
        const staffId = $(this).data('id');
        if (!window.confirm('Delete this staff member? This cannot be undone.')) {
            return;
        }

        $.post(ajaxurl, {
            action: 'yatoon_delete_staff',
            nonce: adminNonce,
            staff_id: staffId
        }, function(resp) {
            if (resp.success) {
                location.reload();
            } else {
                showStaffServicesNotice(resp?.data?.message || 'Failed to delete staff member.', true);
            }
        }).fail(function() {
            showStaffServicesNotice('Could not delete staff member. Please try again.', true);
        });
    });

    $(document).on('change', '#sbs-select-all-services', function() {
        const checked = $(this).is(':checked');
        $('.sbs-service-checkbox').prop('checked', checked);
        $('.sbs-service-checkbox').each(function() {
            updateServiceLabelStyle($(this));
        });
    });

    $(document).on('change', '.sbs-service-checkbox', function() {
        updateServiceLabelStyle($(this));
        const total   = $('.sbs-service-checkbox').length;
        const checked = $('.sbs-service-checkbox:checked').length;
        $('#sbs-select-all-services').prop('indeterminate', checked > 0 && checked < total);
        $('#sbs-select-all-services').prop('checked', checked === total);
    });

    function updateServiceLabelStyle($cb) {
        const $label = $cb.closest('label');
        if ($cb.is(':checked')) {
            $label.css({ 'border-color': '#ec4899', 'background': '#fdf2f8' });
        } else {
            $label.css({ 'border-color': '#ddd', 'background': '' });
        }
    }

    $('.sbs-edit-services').on('click', function() {
        currentStaffId = $(this).data('staff-id');
        const staffName = $(this).data('staff-name');
        $('#sbs-select-all-services').prop('checked', false).prop('indeterminate', false);
        $('#sbs-modal-staff-name').text(staffName);
        $('#sbs-edit-services-modal').fadeIn(200);

        $.ajax({
            url: ajaxurl,
            type: 'POST',
            data: {
                action: 'yatoon_get_staff_services',
                staff_id: currentStaffId,
                nonce: staffServicesNonce
            },
            success: function(response) {
                if (response.success) {
                    let html = '';
                    response.data.services.forEach(function(service) {
                        const borderColor = service.assigned ? '#ec4899' : '#ddd';
                        const bgColor     = service.assigned ? '#fdf2f8' : '';
                        html += `
                            <label style="display:flex; align-items:center; gap:10px; padding:10px 14px; border:1.5px solid ${borderColor}; margin-bottom:8px; border-radius:8px; cursor:pointer; background:${bgColor}; transition:all .15s;">
                                <input type="checkbox"
                                       class="sbs-service-checkbox"
                                       value="${service.id}"
                                       style="width:16px;height:16px;accent-color:#ec4899;flex-shrink:0;"
                                       ${service.assigned ? 'checked' : ''}>
                                <span style="flex:1;"><strong>${service.name}</strong></span>
                                ${service.price > 0 ? '<span style="font-size:12px;color:#6b7280;">$' + service.price + '</span>' : ''}
                            </label>
                        `;
                    });
                    $('#sbs-services-list').html(html);
                    const total = response.data.services.length;
                    const assigned = response.data.services.filter(s => s.assigned).length;
                    $('#sbs-select-all-services')
                        .prop('checked', assigned === total && total > 0)
                        .prop('indeterminate', assigned > 0 && assigned < total);
                } else {
                    showStaffServicesNotice(response?.data?.message || 'Failed to load services.', true);
                    $('#sbs-edit-services-modal').fadeOut(200);
                }
            },
            error: function(xhr) {
                let msg = 'Could not load staff services. Please try again.';
                if (xhr && xhr.responseJSON && xhr.responseJSON.data && xhr.responseJSON.data.message) {
                    msg = xhr.responseJSON.data.message;
                } else if (xhr && xhr.responseText) {
                    msg += ' Server said: ' + xhr.responseText.substring(0, 180);
                }
                showStaffServicesNotice(msg, true);
                $('#sbs-edit-services-modal').fadeOut(200);
            }
        });
    });

    $('#sbs-modal-cancel, #sbs-edit-services-modal').on('click', function(e) {
        if (e.target === this) {
            $('#sbs-edit-services-modal').fadeOut(200);
        }
    });

    $('#sbs-modal-save').on('click', function() {
        const $saveButton = $(this);
        const selectedServices = [];
        $('.sbs-service-checkbox:checked').each(function() {
            selectedServices.push($(this).val());
        });

        $saveButton.prop('disabled', true).text('Saving...');

        $.ajax({
            url: ajaxurl,
            type: 'POST',
            data: {
                action: 'yatoon_update_staff_services',
                staff_id: currentStaffId,
                service_ids: selectedServices,
                nonce: staffServicesNonce
            },
            success: function(response) {
                if (response.success) {
                    showStaffServicesNotice(response?.data?.message || 'Services updated successfully.', false);
                    $('#sbs-edit-services-modal').fadeOut(200);
                    location.reload();
                } else {
                    showStaffServicesNotice(response?.data?.message || 'Failed to save services.', true);
                }
            },
            error: function() {
                showStaffServicesNotice('Could not save staff services. Please try again.', true);
            },
            complete: function() {
                $saveButton.prop('disabled', false).text('Save');
            }
        });
    });
});

jQuery(function($){
    $(document).on('change', '.sbs-bookable-toggle', function(){
        const $cb = $(this);
        const $row = $cb.closest('tr');
        const $label = $cb.siblings('.sbs-toggle-slider').next('.sbs-toggle-label');
        const staffId = $cb.data('id');
        const val = $cb.is(':checked') ? 1 : 0;

        $row.addClass('sbs-saving');

        $.post(ajaxurl, {
            action: 'yatoon_toggle_staff_bookable',
            nonce: yatoonStaffData.toggleNonce,
            staff_id: staffId,
            bookable: val
        }, function(resp){
            $row.removeClass('sbs-saving');
            if (resp.success) {
                $label.text(val ? 'Visible' : 'Hidden');
                $row.attr('data-online', val ? 'visible' : 'hidden').data('online', val ? 'visible' : 'hidden');
            } else {
                $cb.prop('checked', !val);
                $label.text(!val ? 'Visible' : 'Hidden');
                alert('Failed to save. Please try again.');
            }
        }).fail(function(){
            $row.removeClass('sbs-saving');
            $cb.prop('checked', !val);
            $label.text(!val ? 'Visible' : 'Hidden');
        });
    });

    // -- Set PIN modal ------------------------------------------------------
    // Inject modal HTML once
    let yspPinLength = parseInt(yatoonStaffData.pinLength, 10) === 4 ? 4 : 6;
    if (!$('#ysp-pin-modal').length) {
        $('body').append(`
            <div id="ysp-pin-modal" style="display:none;position:fixed;inset:0;z-index:999999;background:rgba(0,0,0,.5);align-items:center;justify-content:center;">
                <div style="background:#fff;border-radius:8px;padding:24px;width:320px;box-shadow:0 8px 32px rgba(0,0,0,.2);">
                    <h3 id="ysp-pin-title" style="margin:0 0 16px;font-size:16px;">Set Portal PIN</h3>
                    <label style="display:block;font-size:13px;font-weight:600;margin-bottom:6px;"><span id="ysp-pin-length-label">${yspPinLength}</span>-digit PIN <span style="font-weight:400;color:#6b7280;">(leave blank to remove)</span></label>
                    <input type="password" id="ysp-pin-input" maxlength="${yspPinLength}" inputmode="numeric" pattern="[0-9]*"
                        style="width:100%;height:42px;border:1.5px solid #d1d5db;border-radius:6px;padding:0 12px;font-size:20px;letter-spacing:.2em;text-align:center;box-sizing:border-box;">
                    <p id="ysp-pin-error" style="color:#dc2626;font-size:13px;min-height:20px;margin:6px 0 0;"></p>
                    <div style="display:flex;gap:8px;margin-top:16px;">
                        <button id="ysp-pin-save" class="button button-primary" style="flex:1;">Save PIN</button>
                        <button id="ysp-pin-cancel" class="button" style="flex:1;">Cancel</button>
                    </div>
                </div>
            </div>
        `);
    }

    let _pinStaffId = null;
    // When the PIN dialog is opened from inside the Edit Staff Member editor
    // we hand the result back instead of reloading, so unsaved edits in that
    // editor survive setting a PIN.
    let _pinDone = null;
    const yspPinNonce = yatoonStaffData.pinNonce;

    function yspOpenPinModal(staffId, staffName, onDone) {
        _pinStaffId = staffId;
        _pinDone = typeof onDone === 'function' ? onDone : null;
        $('#ysp-pin-title').text('Set Portal PIN - ' + (staffName || ''));
        $('#ysp-pin-input').val('');
        $('#ysp-pin-error').text('');
        $('#ysp-pin-modal').css('display','flex');
        setTimeout(() => $('#ysp-pin-input').focus(), 100);
    }

    function yspApplyPinLength(length) {
        yspPinLength = parseInt(length, 10) === 4 ? 4 : 6;
        $('#ysp-pin-length-label').text(yspPinLength);
        $('#ysp-pin-input').attr('maxlength', yspPinLength);
    }

    // Shared with the Edit Staff Member editor, which lives in its own closure.
    window.yatoonStaffPin = {
        open: yspOpenPinModal,
        applyLength: yspApplyPinLength,
        length: function() { return yspPinLength; },
        nonce: yspPinNonce,
        save: function(staffId, pin, onDone) {
            return $.post(ajaxurl, {
                action: 'yatoon_set_staff_pin',
                nonce: yspPinNonce,
                staff_id: staffId,
                pin: pin
            }, onDone);
        }
    };

    $(document).on('click', '.sbs-set-pin-btn', function() {
        yspOpenPinModal($(this).data('id'), $(this).data('name'), null);
    });

    $('#ysp-pin-cancel, #ysp-pin-modal').on('click', function(e) {
        if (e.target === this) $('#ysp-pin-modal').hide();
    });

    // Save PIN
    $(document).on('click', '#ysp-pin-save', function() {
        const pin = $('#ysp-pin-input').val().trim();
        const pinPattern = new RegExp('^\\d{' + yspPinLength + '}$');
        if (pin !== '' && !pinPattern.test(pin)) {
            $('#ysp-pin-error').text('PIN must be exactly ' + yspPinLength + ' digits.');
            return;
        }
        const $btn = $(this).prop('disabled', true).text('Saving...');
        $.post(ajaxurl, {
            action:   'yatoon_set_staff_pin',
            nonce:    yspPinNonce,
            staff_id: _pinStaffId,
            pin:      pin,
        }, function(resp) {
            $btn.prop('disabled', false).text('Save PIN');
            if (resp.success) {
                $('#ysp-pin-modal').hide();
                if (_pinDone) {
                    const done = _pinDone;
                    _pinDone = null;
                    done(pin !== '');
                } else {
                    location.reload();
                }
            } else {
                $('#ysp-pin-error').text(resp.data?.message || 'Failed to save PIN.');
            }
        }).fail(function() {
            $btn.prop('disabled', false).text('Save PIN');
            $('#ysp-pin-error').text('Network error. Please try again.');
        });
    });

    // Allow Enter key to submit
    $(document).on('keydown', '#ysp-pin-input', function(e) {
        if (e.key === 'Enter') $('#ysp-pin-save').trigger('click');
    });

});
