<?php
// phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound
if (!defined('ABSPATH')) {
    exit;
}

$nonce = wp_create_nonce('yatoon_admin_nonce');
$date_ts = strtotime($date . ' 12:00:00');
$prev_date = gmdate('Y-m-d', strtotime('-1 day', $date_ts));
$next_date = gmdate('Y-m-d', strtotime('+1 day', $date_ts));
$today_date = current_time('Y-m-d');

// ── Timezone fix ─────────────────────────────────────────────────────────────
// The DB stores times in the site's local timezone (no UTC offset stored).
// strtotime() silently interprets them as UTC on servers set to UTC, causing
// a 4-hour offset. We parse with explicit local timezone instead.
$_yc_tz_string = wp_timezone_string() ?: 'UTC';
$_yc_local_tz  = new DateTimeZone( $_yc_tz_string );
function yatoon_cal_fmt_time( $db_time, $tz ) {
    if ( empty( $db_time ) ) return '';
    $dt = new DateTime( $db_time, $tz );
    return $dt->format( 'g:i A' );
}

// ── All active staff for filter UI ───────────────────────────────────────────
global $wpdb;
$_yc_all_staff       = $wpdb->get_results( "SELECT id, name FROM {$wpdb->prefix}yatoon_staff WHERE is_active = 1 AND is_bookable = 1 ORDER BY sort_order ASC, name ASC" ); // phpcs:ignore
$_yc_hidden_raw      = get_option( 'yatoon_calendar_hidden_staff', '' );
$_yc_hidden_ids      = array_filter( array_map( 'intval', explode( ',', $_yc_hidden_raw ) ) );

$status_options = array(
    'pending'   => 'Pending',
    'confirmed' => 'Confirmed',
    'completed' => 'Completed',
    'no_show'   => 'No Show',
    'cancelled' => 'Cancelled',
);
$payment_options = array(
    'unpaid'          => 'Unpaid',
    'paid_square_pos' => 'Paid in Square POS',
    'deposit_paid'    => 'Deposit Paid',
    'no_show_fee_charged' => 'No-show Fee Charged',
    'no_show_fee_waived'  => 'No-show Fee Waived',
    'refunded'        => 'Refunded',
    'waived'          => 'Waived',
);
$is_square_mode = get_option('yatoon_active_platform', 'local') === 'square';
$square_no_show_enabled = get_option('yatoon_square_no_show_fee_enabled', '') === '1';
$square_app_url = get_option('yatoon_square_app_url', '');
$square_checkout_url = get_option('yatoon_square_checkout_url', '');
$square_no_show_amount = (float) get_option('yatoon_square_no_show_fee_amount', 25);

$by_staff = array();
foreach ((array) $staff as $person) {
    $by_staff[(int) $person->id] = array(
        'staff'    => $person,
        'bookings' => array(),
    );
}
$by_staff[0] = array(
    'staff'    => (object) array('id' => 0, 'name' => 'Any / Unassigned'),
    'bookings' => array(),
);
foreach ((array) $bookings as $booking) {
    $staff_id = (int) ($booking->staff_id ?? 0);
    if (!isset($by_staff[$staff_id])) {
        $by_staff[$staff_id] = array(
            'staff'    => (object) array('id' => $staff_id, 'name' => $booking->staff_name ?: 'Inactive Staff'),
            'bookings' => array(),
        );
    }
    $by_staff[$staff_id]['bookings'][] = $booking;
}

$total_revenue = 0;
$unpaid_count = 0;
foreach ((array) $bookings as $booking) {
    $total_revenue += (float) $booking->total_price;
    if (empty($booking->payment_status) || $booking->payment_status === 'unpaid') {
        $unpaid_count++;
    }
}
?>

<div class="wrap" id="yatoon-calendar-wrap">
    <h1>Staff Calendar</h1>

    <style>
    #yatoon-calendar-wrap .yc-toolbar{display:flex;align-items:center;justify-content:space-between;gap:12px;margin:14px 0 18px;flex-wrap:wrap;}
    #yatoon-calendar-wrap .yc-date-nav{display:flex;align-items:center;gap:8px;flex-wrap:wrap;}
    #yatoon-calendar-wrap .yc-date-title{font-size:18px;font-weight:700;color:#111827;min-width:190px;text-align:center;}
    #yatoon-calendar-wrap .yc-stats{display:flex;gap:10px;flex-wrap:wrap;}
    #yatoon-calendar-wrap .yc-stat{background:#fff;border:1px solid #dcdcde;border-radius:8px;padding:8px 12px;min-width:110px;}
    #yatoon-calendar-wrap .yc-stat strong{display:block;font-size:18px;color:#111827;line-height:1.1;}
    #yatoon-calendar-wrap .yc-stat span{font-size:11px;color:#6b7280;text-transform:uppercase;letter-spacing:.04em;}
    #yatoon-calendar-wrap .yc-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:14px;}
    #yatoon-calendar-wrap .yc-col{background:#fff;border:1px solid #dcdcde;border-radius:8px;overflow:hidden;min-height:160px;}
    #yatoon-calendar-wrap .yc-col-head{padding:12px 14px;background:#f6f7f7;border-bottom:1px solid #dcdcde;display:flex;justify-content:space-between;align-items:center;}
    #yatoon-calendar-wrap .yc-col-head h2{font-size:15px;margin:0;color:#1f2937;}
    #yatoon-calendar-wrap .yc-count{font-size:12px;color:#6b7280;}
    #yatoon-calendar-wrap .yc-card{padding:12px 14px;border-bottom:1px solid #f0f0f1;}
    #yatoon-calendar-wrap .yc-card:last-child{border-bottom:none;}
    #yatoon-calendar-wrap .yc-card[draggable="true"]{cursor:grab;touch-action:none;}
    #yatoon-calendar-wrap .yc-card.is-dragging{opacity:.62;box-shadow:0 12px 28px rgba(15,23,42,.18);cursor:grabbing;}
    #yatoon-calendar-wrap .yc-col.is-drop-target{outline:2px solid #16a34a;outline-offset:-4px;background:#f0fdf4;}
    #yatoon-calendar-wrap .yc-time{font-weight:700;color:#111827;margin-bottom:4px;}
    #yatoon-calendar-wrap .yc-service{font-size:14px;color:#374151;margin-bottom:4px;}
    #yatoon-calendar-wrap .yc-client{font-size:13px;color:#4b5563;margin-bottom:8px;}
    #yatoon-calendar-wrap .yc-controls{display:grid;grid-template-columns:1fr;gap:6px;}
    #yatoon-calendar-wrap .yc-controls select{width:100%;font-size:12px;min-height:30px;}
    #yatoon-calendar-wrap .yc-reschedule-toggle{width:100%;justify-content:center;}
    #yatoon-calendar-wrap .yc-reschedule-panel{display:none;margin-top:8px;padding:10px;border:1px solid #bbf7d0;border-radius:8px;background:#f0fdf4;}
    #yatoon-calendar-wrap .yc-reschedule-panel.is-open{display:block;}
    #yatoon-calendar-wrap .yc-reschedule-row{display:grid;grid-template-columns:1fr;gap:8px;margin-bottom:8px;}
    #yatoon-calendar-wrap .yc-reschedule-row input{width:100%;}
    #yatoon-calendar-wrap .yc-slot-list{display:flex;gap:6px;flex-wrap:wrap;min-height:34px;}
    #yatoon-calendar-wrap .yc-slot-chip{border:1px solid #86efac;background:#fff;border-radius:999px;padding:5px 10px;font-size:12px;cursor:pointer;}
    #yatoon-calendar-wrap .yc-slot-chip.is-selected{background:#16a34a;border-color:#16a34a;color:#fff;}
    #yatoon-calendar-wrap .yc-reschedule-actions{display:flex;align-items:center;gap:8px;justify-content:space-between;flex-wrap:wrap;margin-top:8px;}
    #yatoon-calendar-wrap .yc-reschedule-msg{font-size:12px;color:#4b5563;margin-top:6px;}
    #yatoon-calendar-wrap .yc-reschedule-msg.is-error{color:#b91c1c;}
    #yatoon-calendar-wrap .yc-no-show-tools{display:none;gap:6px;flex-wrap:wrap;margin-top:8px;padding:8px;border:1px solid #fecaca;border-radius:8px;background:#fff;}
    #yatoon-calendar-wrap .yc-card.yc-status-no_show .yc-no-show-tools{display:flex;}
    #yatoon-calendar-wrap .yc-no-show-tools .button{min-height:28px;font-size:12px;line-height:26px;}
    #yatoon-calendar-wrap .yc-no-show-note{width:100%;font-size:12px;color:#991b1b;}
    #yatoon-calendar-wrap .yc-empty{padding:18px 14px;color:#9ca3af;font-size:13px;text-align:center;}
    #yatoon-calendar-wrap .yc-status-completed{border-left:4px solid #16a34a;}
    #yatoon-calendar-wrap .yc-status-no_show{border-left:4px solid #dc2626;background:#fff7f7;}
    #yatoon-calendar-wrap .yc-status-cancelled{border-left:4px solid #6b7280;opacity:.72;}
    /* Highlight cards for bookings that include a customer design/photo upload */
    #yatoon-calendar-wrap .yc-card.yc-has-design{background:#fef3c7;box-shadow:inset 5px 0 0 #f59e0b;position:relative;}
    #yatoon-calendar-wrap .yc-card.yc-has-design.yc-status-no_show{background:#fef3c7;}
    #yatoon-calendar-wrap .yc-card.yc-has-design::after{content:'\1F4F7';position:absolute;top:-6px;right:-6px;width:20px;height:20px;line-height:20px;font-size:11px;text-align:center;background:#f59e0b;border-radius:50%;box-shadow:0 1px 3px rgba(0,0,0,.35);z-index:2;}
    #yatoon-calendar-wrap .yc-view-details{width:100%;justify-content:center;background:#fff;border-color:#c7d2fe;color:#3730a3;font-weight:600;}
    .yc-detail-overlay{display:none;position:fixed;inset:0;background:rgba(15,23,42,.5);z-index:100000;align-items:center;justify-content:center;padding:20px;}
    .yc-detail-overlay.is-open{display:flex;}
    .yc-detail-modal{background:#fff;border-radius:12px;max-width:480px;width:100%;max-height:85vh;overflow-y:auto;padding:28px 24px 24px;position:relative;box-shadow:0 20px 50px rgba(0,0,0,.3);}
    .yc-detail-modal h2{margin:0 0 16px;font-size:18px;color:#111827;padding-right:24px;}
    .yc-detail-close{position:absolute;top:14px;right:14px;background:none;border:none;font-size:22px;line-height:1;cursor:pointer;color:#6b7280;}
    .yc-detail-row{display:flex;justify-content:space-between;gap:12px;padding:8px 0;border-bottom:1px solid #f0f0f1;font-size:13px;}
    .yc-detail-row strong{color:#6b7280;font-weight:600;}
    .yc-detail-row span{color:#111827;text-align:right;}
    .yc-detail-note{margin-top:12px;padding:10px 12px;background:#f9fafb;border-radius:8px;font-size:13px;}
    .yc-detail-note p{margin:6px 0 0;color:#374151;}
    .yc-detail-design{margin-top:14px;font-size:13px;}
    .yc-detail-design img{max-width:100%;border-radius:8px;margin-top:8px;display:block;}
    /* Calendar settings panel */
    #yatoon-calendar-wrap .yc-settings-bar{background:#fff;border:1px solid #dcdcde;border-radius:8px;padding:12px 16px;margin-bottom:14px;display:flex;gap:24px;flex-wrap:wrap;align-items:flex-start;}
    #yatoon-calendar-wrap .yc-settings-bar h3{margin:0 0 8px;font-size:13px;color:#374151;text-transform:uppercase;letter-spacing:.04em;}
    #yatoon-calendar-wrap .yc-staff-filters label{display:inline-flex;align-items:center;gap:5px;margin-right:12px;font-size:13px;cursor:pointer;}
    #yatoon-calendar-wrap .yc-tz-row{display:flex;align-items:center;gap:8px;font-size:13px;}
    #yatoon-calendar-wrap .yc-tz-row select{font-size:13px;}
    @media (max-width:782px){#yatoon-calendar-wrap .yc-date-title{text-align:left;min-width:0;width:100%;}}
    #yatoon-calendar-wrap .yc-mobile-staff-tabs{display:none;}
    @media (max-width:900px){
        #yatoon-calendar-wrap .yc-mobile-staff-tabs{
            display:flex;gap:7px;margin:0 0 12px;padding:2px 0 6px;
            overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none;
        }
        #yatoon-calendar-wrap .yc-mobile-staff-tabs::-webkit-scrollbar{display:none;}
        #yatoon-calendar-wrap .yc-mobile-staff-tabs button{
            display:inline-flex;flex:0 0 auto;align-items:center;gap:7px;
            min-height:36px;padding:7px 12px;border:1px solid #e5e7eb;
            border-radius:999px;background:#fff;color:#111827;font-weight:650;
            font-size:13px;cursor:pointer;
        }
        #yatoon-calendar-wrap .yc-mobile-staff-tabs button.is-active{
            border-color:#111827;background:#111827;color:#fff;
        }
        #yatoon-calendar-wrap .yc-mobile-staff-tabs b{
            display:grid;min-width:20px;height:20px;place-items:center;
            border-radius:999px;background:rgba(127,127,127,.16);font-size:11px;
        }
        #yatoon-calendar-wrap .yc-mobile-staff-tabs button.is-active b{background:rgba(255,255,255,.22);}
        /* On narrow screens, stack staff columns instead of a horizontal grid
           so the quick-jump tabs above have somewhere useful to scroll to. */
        #yatoon-calendar-wrap .yc-grid{grid-template-columns:1fr !important;}
    }
    </style>

    <!-- Calendar settings bar: timezone + staff filter -->
    <div class="yc-settings-bar">
        <div>
            <h3>Timezone</h3>
            <div class="yc-tz-row">
                <span><?php echo esc_html( $_yc_tz_string ); ?></span>
                <span class="description">Uses the WordPress site timezone.</span>
            </div>
        </div>
        <div>
            <h3>Show Staff Columns</h3>
            <div class="yc-staff-filters">
                <?php foreach ( $_yc_all_staff as $sf ) : ?>
                    <label>
                        <input type="checkbox" class="yc-staff-toggle"
                            data-staff-id="<?php echo intval( $sf->id ); ?>"
                            <?php checked( ! in_array( intval( $sf->id ), $_yc_hidden_ids, true ) ); ?>>
                        <?php echo esc_html( $sf->name ); ?>
                    </label>
                <?php endforeach; ?>
            </div>
        </div>
    </div>

    <div class="yc-toolbar">
        <div class="yc-date-nav">
            <a class="button" href="<?php echo esc_url(admin_url('admin.php?page=yatoon-calendar&date=' . $prev_date)); ?>">&larr; Prev</a>
            <a class="button" href="<?php echo esc_url(admin_url('admin.php?page=yatoon-calendar&date=' . $today_date)); ?>">Today</a>
            <a class="button" href="<?php echo esc_url(admin_url('admin.php?page=yatoon-calendar&date=' . $next_date)); ?>">Next &rarr;</a>
            <form method="get" style="display:flex;gap:6px;align-items:center;">
                <input type="hidden" name="page" value="yatoon-calendar">
                <input type="date" name="date" value="<?php echo esc_attr($date); ?>">
                <button type="submit" class="button">Go</button>
            </form>
        </div>
        <div class="yc-date-title"><?php echo esc_html(date_i18n('D, M j, Y', $date_ts)); ?></div>
        <div class="yc-stats">
            <div class="yc-stat"><strong><?php echo count((array) $bookings); ?></strong><span>Bookings</span></div>
            <div class="yc-stat"><strong>$<?php echo esc_html(number_format($total_revenue, 0)); ?></strong><span>Scheduled</span></div>
            <div class="yc-stat"><strong><?php echo intval($unpaid_count); ?></strong><span>Unpaid</span></div>
        </div>
    </div>

    <div class="yc-mobile-staff-tabs" aria-label="Choose employee">
        <?php foreach ($by_staff as $group) : ?>
            <?php if ((int) $group['staff']->id === 0 && empty($group['bookings'])) { continue; } ?>
            <button type="button" data-calendar-staff-target="<?php echo intval($group['staff']->id); ?>">
                <span><?php echo esc_html($group['staff']->name); ?></span>
                <b><?php echo count($group['bookings']); ?></b>
            </button>
        <?php endforeach; ?>
    </div>

    <div class="yc-grid">
        <?php foreach ($by_staff as $group) : ?>
            <?php if ((int) $group['staff']->id === 0 && empty($group['bookings'])) { continue; } ?>
            <section class="yc-col" data-staff-id="<?php echo intval($group['staff']->id); ?>" data-staff-name="<?php echo esc_attr($group['staff']->name); ?>">
                <div class="yc-col-head">
                    <h2><?php echo esc_html($group['staff']->name); ?></h2>
                    <span class="yc-count"><?php echo count($group['bookings']); ?> appt</span>
                </div>
                <?php if (empty($group['bookings'])) : ?>
                    <div class="yc-empty">No bookings</div>
                <?php else : ?>
                    <?php foreach ($group['bookings'] as $booking) : ?>
                        <div class="yc-card yc-status-<?php echo esc_attr($booking->status ?: 'pending'); ?><?php echo !empty($booking->design_image_url) ? ' yc-has-design' : ''; ?>"
                            draggable="true"
                            data-booking-id="<?php echo intval($booking->id); ?>"
                            data-service-id="<?php echo intval($booking->service_id); ?>"
                            data-staff-id="<?php echo intval($booking->staff_id); ?>"
                            data-design-upload="<?php echo esc_attr(!empty($booking->design_image_url) ? '1' : '0'); ?>"
                            data-start-time="<?php echo esc_attr($booking->start_time); ?>">
                            <div class="yc-time">
                                <?php echo esc_html( yatoon_cal_fmt_time( $booking->start_time, $_yc_local_tz ) ); ?>
                                - <?php echo esc_html( yatoon_cal_fmt_time( $booking->end_time, $_yc_local_tz ) ); ?>
                            </div>
                            <div class="yc-service"><?php echo esc_html($booking->service_name ?: 'Service'); ?> - $<?php echo esc_html(number_format((float) $booking->total_price, 2)); ?></div>
                            <div class="yc-client">
                                <strong><?php echo esc_html($booking->customer_name); ?></strong><br>
                                <?php echo esc_html($booking->customer_phone ?: $booking->customer_email); ?>
                            </div>
                            <div class="yc-controls">
                                <button type="button" class="button yc-view-details" data-booking-id="<?php echo intval($booking->id); ?>">View details</button>
                                <select class="yc-status-select" data-booking-id="<?php echo intval($booking->id); ?>">
                                    <?php foreach ($status_options as $value => $label) : ?>
                                        <option value="<?php echo esc_attr($value); ?>" <?php selected($booking->status ?: 'pending', $value); ?>><?php echo esc_html($label); ?></option>
                                    <?php endforeach; ?>
                                </select>
                                <select class="yc-payment-select" data-booking-id="<?php echo intval($booking->id); ?>">
                                    <?php foreach ($payment_options as $value => $label) : ?>
                                        <option value="<?php echo esc_attr($value); ?>" <?php selected($booking->payment_status ?: 'unpaid', $value); ?>><?php echo esc_html($label); ?></option>
                                    <?php endforeach; ?>
                                </select>
                                <button type="button" class="button yc-reschedule-toggle">Move / Reschedule</button>
                                <div class="yc-reschedule-panel" aria-live="polite">
                                    <div class="yc-reschedule-row">
                                        <label>
                                            New date
                                            <input type="date" class="yc-reschedule-date" value="<?php echo esc_attr($date); ?>">
                                        </label>
                                    </div>
                                    <div class="yc-slot-list">
                                        <span class="description">Choose a date to load available times.</span>
                                    </div>
                                    <div class="yc-reschedule-actions">
                                        <span class="description">You'll be asked how to notify the customer when you save.</span>
                                        <button type="button" class="button button-primary yc-reschedule-save" disabled>Save move</button>
                                    </div>
                                    <div class="yc-reschedule-msg"></div>
                                </div>
                                <?php if ($is_square_mode && $square_no_show_enabled) : ?>
                                    <div class="yc-no-show-tools">
                                        <div class="yc-no-show-note">Square no-show fee: $<?php echo esc_html(number_format($square_no_show_amount, 2)); ?>. Open Square, charge if appropriate, then record the result.</div>
                                        <?php if ($square_app_url) : ?>
                                            <a class="button" href="<?php echo esc_url($square_app_url); ?>" target="_blank" rel="noopener noreferrer">Open Square App</a>
                                        <?php endif; ?>
                                        <?php if ($square_checkout_url) : ?>
                                            <a class="button" href="<?php echo esc_url($square_checkout_url); ?>" target="_blank" rel="noopener noreferrer">Open Square Checkout</a>
                                        <?php endif; ?>
                                        <button type="button" class="button yc-no-show-fee" data-booking-id="<?php echo intval($booking->id); ?>" data-status="no_show_fee_charged">Mark fee charged</button>
                                        <button type="button" class="button yc-no-show-fee" data-booking-id="<?php echo intval($booking->id); ?>" data-status="no_show_fee_waived">Waive fee</button>
                                    </div>
                                <?php endif; ?>
                            </div>
                        </div>
                    <?php endforeach; ?>
                <?php endif; ?>
            </section>
        <?php endforeach; ?>
    </div>
</div>

<div id="yc-detail-overlay" class="yc-detail-overlay" aria-hidden="true">
    <div class="yc-detail-modal" role="dialog" aria-modal="true">
        <button type="button" class="yc-detail-close" id="yc-detail-close" aria-label="Close">&times;</button>
        <div id="yc-detail-body" class="yc-detail-body"></div>
    </div>
</div>

<script>
window.yatoonCalendarBookings = <?php
    $_yc_detail_map = array();
    foreach ( (array) $bookings as $_yc_b ) {
        $_yc_detail_map[ intval( $_yc_b->id ) ] = array(
            'id'               => intval( $_yc_b->id ),
            'customer_name'    => $_yc_b->customer_name,
            'customer_email'   => $_yc_b->customer_email,
            'customer_phone'   => $_yc_b->customer_phone,
            'service_name'     => $_yc_b->service_name ?: 'Service',
            'staff_name'       => $_yc_b->staff_name ?: 'N/A',
            'start_time'       => yatoon_cal_fmt_time( $_yc_b->start_time, $_yc_local_tz ),
            'end_time'         => yatoon_cal_fmt_time( $_yc_b->end_time, $_yc_local_tz ),
            'status'           => $_yc_b->status ?: 'pending',
            'payment_status'   => $_yc_b->payment_status ?: 'unpaid',
            'payment_note'     => $_yc_b->payment_note,
            'total_price'      => number_format( (float) $_yc_b->total_price, 2 ),
            'notes'            => $_yc_b->notes,
            'design_image_url' => $_yc_b->design_image_url,
            'consent_accepted' => ! empty( $_yc_b->consent_accepted ),
            'policy_acknowledged' => ! empty( $_yc_b->policy_acknowledged ),
        );
    }
    echo wp_json_encode( $_yc_detail_map, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT );
?>;
</script>

<script>
jQuery(function($){
    const nonce = '<?php echo esc_js($nonce); ?>';

    function showCardMessage($card, message, isError) {
        const $msg = $card.find('.yc-reschedule-msg').first();
        $msg.text(message || '').toggleClass('is-error', !!isError);
    }

    function moveBooking($card, staffId, startAt, notifyMethod) {
        $card.addClass('is-saving');
        showCardMessage($card, 'Saving move...', false);
        return $.post(ajaxurl, {
            action: 'yatoon_admin_reschedule_booking',
            nonce,
            booking_id: $card.data('booking-id'),
            staff_id: staffId,
            start_at: startAt,
            notify_method: notifyMethod || 'none'
        }, function(res) {
            if (!res.success) {
                const msg = res.data && res.data.message ? res.data.message : 'Could not reschedule booking.';
                showCardMessage($card, msg, true);
                return;
            }
            location.href = '<?php echo esc_js(admin_url('admin.php?page=yatoon-calendar&date=')); ?>' + encodeURIComponent(res.data.date || '<?php echo esc_js($date); ?>');
        }).fail(function() {
            showCardMessage($card, 'Network error while rescheduling.', true);
        }).always(function() {
            $card.removeClass('is-saving is-dragging');
            $('.yc-col').removeClass('is-drop-target');
        });
    }

    function loadRescheduleSlots($card) {
        const $panel = $card.find('.yc-reschedule-panel');
        const date = $panel.find('.yc-reschedule-date').val();
        const staffId = $card.data('staff-id') || $card.closest('.yc-col').data('staff-id');
        const $slots = $panel.find('.yc-slot-list');
        const $save = $panel.find('.yc-reschedule-save');

        $save.prop('disabled', true).removeData('start-at');
        $slots.html('<span class="description">Loading times...</span>');
        showCardMessage($card, '', false);

        $.post(ajaxurl, {
            action: 'yatoon_get_admin_reschedule_slots',
            nonce,
            booking_id: $card.data('booking-id'),
            staff_id: staffId,
            date
        }, function(res) {
            if (!res.success) {
                const msg = res.data && res.data.message ? res.data.message : 'Could not load times.';
                $slots.html('<span class="description">' + msg + '</span>');
                return;
            }
            const slots = (res.data && res.data.slots) ? res.data.slots : [];
            if (!slots.length) {
                $slots.html('<span class="description">No available times for this date.</span>');
                return;
            }
            $slots.html(slots.map(function(slot) {
                return '<button type="button" class="yc-slot-chip" data-start-at="' + String(slot.datetime || '').replace(/"/g, '&quot;') + '">' + String(slot.display || '') + '</button>';
            }).join(''));
        }).fail(function() {
            $slots.html('<span class="description">Network error while loading times.</span>');
        });
    }

    let draggedCard = null;
    $(document).on('dragstart', '.yc-card[draggable="true"]', function(e) {
        draggedCard = this;
        $(this).addClass('is-dragging');
        e.originalEvent.dataTransfer.effectAllowed = 'move';
        e.originalEvent.dataTransfer.setData('text/plain', $(this).data('booking-id'));
    });

    $(document).on('dragend', '.yc-card[draggable="true"]', function() {
        $(this).removeClass('is-dragging');
        $('.yc-col').removeClass('is-drop-target');
        draggedCard = null;
    });

    $(document).on('dragover', '.yc-col', function(e) {
        if (!draggedCard) return;
        e.preventDefault();
        $('.yc-col').removeClass('is-drop-target');
        $(this).addClass('is-drop-target');
    });

    $(document).on('drop', '.yc-col', function(e) {
        if (!draggedCard) return;
        e.preventDefault();
        const $card = $(draggedCard);
        const staffId = $(this).data('staff-id');
        if (!staffId || Number(staffId) === Number($card.data('staff-id'))) return;
        const staffName = $(this).data('staff-name') || 'this staff member';
        if (!window.confirm('Move this booking to ' + staffName + ' at the same time?')) return;
        window.yatoonPromptNotifyMethod({
            title: 'Notify the customer about this move?'
        }, function(method) {
            moveBooking($card, staffId, $card.data('start-time'), method);
        });
    });

    let touchDrag = null;
    $(document).on('pointerdown', '.yc-card[draggable="true"]', function(e) {
        if (e.pointerType === 'mouse' || $(e.target).closest('select,button,input,a,label').length) return;
        touchDrag = { card: this, pointerId: e.pointerId, startX: e.clientX, startY: e.clientY, active: false };
    });
    $(document).on('pointermove', function(e) {
        if (!touchDrag || touchDrag.pointerId !== e.pointerId) return;
        const moved = Math.abs(e.clientX - touchDrag.startX) + Math.abs(e.clientY - touchDrag.startY);
        if (moved > 18) {
            touchDrag.active = true;
            $(touchDrag.card).addClass('is-dragging');
            const el = document.elementFromPoint(e.clientX, e.clientY);
            $('.yc-col').removeClass('is-drop-target');
            $(el).closest('.yc-col').addClass('is-drop-target');
        }
    });
    $(document).on('pointerup pointercancel', function(e) {
        if (!touchDrag || touchDrag.pointerId !== e.pointerId) return;
        const $card = $(touchDrag.card);
        if (touchDrag.active) {
            const el = document.elementFromPoint(e.clientX, e.clientY);
            const $col = $(el).closest('.yc-col');
            const staffId = $col.data('staff-id');
            if (staffId && Number(staffId) !== Number($card.data('staff-id')) && window.confirm('Move this booking to ' + ($col.data('staff-name') || 'this staff member') + ' at the same time?')) {
                window.yatoonPromptNotifyMethod({
                    title: 'Notify the customer about this move?'
                }, function(method) {
                    moveBooking($card, staffId, $card.data('start-time'), method);
                });
            }
        }
        $card.removeClass('is-dragging');
        $('.yc-col').removeClass('is-drop-target');
        touchDrag = null;
    });

    $(document).on('click', '.yc-reschedule-toggle', function() {
        const $card = $(this).closest('.yc-card');
        const $panel = $card.find('.yc-reschedule-panel');
        $('.yc-reschedule-panel').not($panel).removeClass('is-open');
        $panel.toggleClass('is-open');
        if ($panel.hasClass('is-open')) loadRescheduleSlots($card);
    });

    $(document).on('change', '.yc-reschedule-date', function() {
        loadRescheduleSlots($(this).closest('.yc-card'));
    });

    $(document).on('click', '.yc-slot-chip', function() {
        const $chip = $(this);
        const $panel = $chip.closest('.yc-reschedule-panel');
        $panel.find('.yc-slot-chip').removeClass('is-selected');
        $chip.addClass('is-selected');
        $panel.find('.yc-reschedule-save').prop('disabled', false).data('start-at', $chip.data('start-at'));
    });

    $(document).on('click', '.yc-reschedule-save', function() {
        const $btn = $(this);
        const $card = $btn.closest('.yc-card');
        const staffId = $card.data('staff-id') || $card.closest('.yc-col').data('staff-id');
        const startAt = $btn.data('start-at');
        if (!startAt) return;
        window.yatoonPromptNotifyMethod({
            title: 'Notify the customer about this move?'
        }, function(method) {
            moveBooking($card, staffId, startAt, method);
        });
    });

    $(document).on('change', '.yc-status-select', function(){
        const $sel = $(this);
        $.post(ajaxurl, {
            action: 'yatoon_update_booking_status',
            nonce,
            booking_id: $sel.data('booking-id'),
            status: $sel.val()
        }, function(res){
            if (!res.success) {
                alert('Could not update booking status.');
            } else {
                const $card = $sel.closest('.yc-card');
                $card.removeClass('yc-status-pending yc-status-confirmed yc-status-completed yc-status-no_show yc-status-cancelled')
                    .addClass('yc-status-' + $sel.val());
            }
        });
    });

    $(document).on('change', '.yc-payment-select', function(){
        const $sel = $(this);
        const note = $sel.val() === 'paid_square_pos' ? 'Paid in Square POS' : '';
        $.post(ajaxurl, {
            action: 'yatoon_update_payment_status',
            nonce,
            booking_id: $sel.data('booking-id'),
            payment_status: $sel.val(),
            payment_note: note
        }, function(res){
            if (!res.success) {
                alert('Could not update payment status.');
            }
        });
    });

    $(document).on('click', '.yc-no-show-fee', function(){
        const $btn = $(this);
        const status = $btn.data('status');
        const note = status === 'no_show_fee_charged' ? 'No-show fee charged in Square' : 'No-show fee waived';
        $btn.prop('disabled', true);
        $.post(ajaxurl, {
            action: 'yatoon_update_payment_status',
            nonce,
            booking_id: $btn.data('booking-id'),
            payment_status: status,
            payment_note: note
        }, function(res){
            if (!res.success) {
                alert('Could not update no-show fee status.');
            } else {
                $btn.closest('.yc-card').find('.yc-payment-select').val(status);
            }
        }).always(function(){
            $btn.prop('disabled', false);
        });
    });

    // ── Staff column toggle ───────────────────────────────────────────────────
    $(document).on('change', '.yc-staff-toggle', function() {
        const hiddenIds = [];
        $('.yc-staff-toggle').each(function() {
            if (!$(this).is(':checked')) hiddenIds.push($(this).data('staff-id'));
        });
        $.post(ajaxurl, {
            action: 'yatoon_save_calendar_staff_filter',
            nonce,
            hidden_staff: hiddenIds.join(',')
        }, function(res) {
            if (res.success) location.reload();
        });
    });

    $(document).on('click', '[data-calendar-staff-target]', function() {
        const staffId = $(this).data('calendar-staff-target');
        const $grid = $('.yc-grid');
        const $target = $('.yc-col[data-staff-id="' + staffId + '"]').first();
        if (!$grid.length || !$target.length) return;
        $('[data-calendar-staff-target]').removeClass('is-active');
        $(this).addClass('is-active');
        $target.get(0).scrollIntoView({ behavior: 'smooth', block: 'start' });
    });
    $('[data-calendar-staff-target]').first().addClass('is-active');

    // ── Booking detail modal ─────────────────────────────────────────────────
    function ycEscapeHTML(str) {
        return String(str == null ? '' : str).replace(/[&<>"']/g, function(m) {
            return ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'})[m];
        });
    }

    function ycStatusLabel(status) {
        const labels = { pending: 'Pending', confirmed: 'Confirmed', completed: 'Completed', no_show: 'No-show', cancelled: 'Cancelled' };
        return labels[status] || status;
    }

    $(document).on('click', '.yc-view-details', function(e) {
        e.preventDefault();
        e.stopPropagation();
        const id = $(this).data('booking-id');
        const b = (window.yatoonCalendarBookings || {})[id];
        if (!b) return;
        let html = '';
        html += '<h2>' + ycEscapeHTML(b.customer_name || 'Appointment') + '</h2>';
        html += '<div class="yc-detail-row"><strong>Service</strong><span>' + ycEscapeHTML(b.service_name) + ' - $' + ycEscapeHTML(b.total_price) + '</span></div>';
        html += '<div class="yc-detail-row"><strong>Staff</strong><span>' + ycEscapeHTML(b.staff_name) + '</span></div>';
        html += '<div class="yc-detail-row"><strong>Time</strong><span>' + ycEscapeHTML(b.start_time) + ' - ' + ycEscapeHTML(b.end_time) + '</span></div>';
        html += '<div class="yc-detail-row"><strong>Status</strong><span>' + ycEscapeHTML(ycStatusLabel(b.status)) + '</span></div>';
        html += '<div class="yc-detail-row"><strong>Payment</strong><span>' + ycEscapeHTML(ycStatusLabel(b.payment_status)) + (b.payment_note ? ' (' + ycEscapeHTML(b.payment_note) + ')' : '') + '</span></div>';
        if (b.customer_phone) html += '<div class="yc-detail-row"><strong>Phone</strong><span>' + ycEscapeHTML(b.customer_phone) + '</span></div>';
        if (b.customer_email) html += '<div class="yc-detail-row"><strong>Email</strong><span>' + ycEscapeHTML(b.customer_email) + '</span></div>';
        if (b.consent_accepted) html += '<div class="yc-detail-row"><strong>Consent</strong><span>Signed</span></div>';
        if (b.policy_acknowledged) html += '<div class="yc-detail-row"><strong>Policy</strong><span>Acknowledged</span></div>';
        if (b.notes) html += '<div class="yc-detail-note"><strong>Appointment note</strong><p>' + ycEscapeHTML(b.notes) + '</p></div>';
        if (b.design_image_url) {
            html += '<div class="yc-detail-design"><strong>Design reference</strong><br>' +
                '<a href="' + ycEscapeHTML(b.design_image_url) + '" target="_blank" rel="noopener"><img src="' + ycEscapeHTML(b.design_image_url) + '" alt=""></a></div>';
        }
        $('#yc-detail-body').html(html);
        $('#yc-detail-overlay').addClass('is-open').attr('aria-hidden', 'false');
    });

    function ycCloseDetail() {
        $('#yc-detail-overlay').removeClass('is-open').attr('aria-hidden', 'true');
    }
    $('#yc-detail-close').on('click', ycCloseDetail);
    $('#yc-detail-overlay').on('click', function(e) {
        if (e.target === this) ycCloseDetail();
    });
    $(document).on('keydown', function(e) {
        if (e.key === 'Escape') ycCloseDetail();
    });

});
</script>
