<?php
// phpcs:disable WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.InputNotValidated
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare, WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber
// phpcs:disable PluginCheck.Security.DirectDB.UnescapedDBParameter
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
if ( ! defined( 'ABSPATH' ) ) { exit; }

/**
 * YATOON_Notifications
 *
 * Handles:
 *  1. Appointment Reminder emails  - sent X hours before appointment
 *  2. Review Request emails        - sent X hours after appointment ends
 *
 * Both features are free, email-based, fully configurable from the admin page.
 */
class YATOON_Notifications {

    public function __construct() {
        // Register the two custom cron hooks
        add_action( 'yatoon_send_reminder',       array( $this, 'send_reminder_email' ),      10, 1 );
        add_action( 'yatoon_send_review_request', array( $this, 'send_review_request_email' ), 10, 1 );
        add_action( 'yatoon_send_no_show_followup', array( $this, 'send_no_show_followup_email' ), 10, 1 );
        add_action( 'yatoon_booking_marked_no_show', array( $this, 'schedule_no_show_followup' ), 10, 1 );

        // Schedule cron jobs whenever a booking is saved to DB
        add_action( 'yatoon_booking_created', array( $this, 'schedule_for_booking' ), 10, 1 );

        // Auto-upsert client record on every new booking
        add_action( 'yatoon_booking_created', array( $this, 'upsert_client' ), 20, 1 );

        // Admin AJAX: send test emails
        add_action( 'wp_ajax_yatoon_test_reminder_email',       array( $this, 'ajax_test_reminder' ) );
        add_action( 'wp_ajax_yatoon_test_review_request_email', array( $this, 'ajax_test_review' ) );
        add_action( 'wp_ajax_yatoon_test_cancel_email',         array( $this, 'ajax_test_cancel_email' ) );
        add_action( 'wp_ajax_yatoon_test_reschedule_email',     array( $this, 'ajax_test_reschedule_email' ) );
        add_action( 'wp_ajax_yatoon_test_no_show_email',        array( $this, 'ajax_test_no_show_email' ) );

        // Admin AJAX: save notification settings
        add_action( 'wp_ajax_yatoon_save_notifications', array( $this, 'ajax_save_settings' ) );
    }

    // -------------------------------------------------------------------------
    // Schedule cron events when a booking is created
    // -------------------------------------------------------------------------

    /**
     * Called via do_action('yatoon_booking_created', $booking_data) from class-yatoon-ajax.php
     * $booking_data must contain: booking_id, customer_email, customer_name, start_time, end_time,
     *                              service_name, staff_name, total_price, notes
     */
    public function schedule_for_booking( $booking ) {
        if ( empty( $booking['customer_email'] ) || empty( $booking['start_time'] ) ) {
            return;
        }

        $booking_id = $booking['booking_id'] ?? '';
        if ( empty( $booking_id ) ) return;

        // -- 1. Reminder -------------------------------------------------------
        if ( get_option( 'yatoon_reminder_enabled', '1' ) === '1' ) {
            $hours_before = intval( get_option( 'yatoon_reminder_hours_before', 24 ) );
            if ( $hours_before > 0 ) {
                $start_ts      = strtotime( $booking['start_time'] );
                $reminder_ts   = $start_ts - ( $hours_before * HOUR_IN_SECONDS );
                if ( $reminder_ts > time() ) {
                    // Avoid duplicate schedules
                    if ( ! wp_next_scheduled( 'yatoon_send_reminder', array( $booking_id ) ) ) {
                        wp_schedule_single_event( $reminder_ts, 'yatoon_send_reminder', array( $booking_id ) );
                    }
                }
            }
        }

        // -- 2. Review Request -------------------------------------------------
        if ( get_option( 'yatoon_review_enabled', '1' ) === '1' ) {
            $hours_after = intval( get_option( 'yatoon_review_hours_after', 2 ) );
            if ( $hours_after >= 0 ) {
                $end_ts    = strtotime( $booking['end_time'] );
                $review_ts = $end_ts + ( $hours_after * HOUR_IN_SECONDS );
                if ( $review_ts > time() ) {
                    if ( ! wp_next_scheduled( 'yatoon_send_review_request', array( $booking_id ) ) ) {
                        wp_schedule_single_event( $review_ts, 'yatoon_send_review_request', array( $booking_id ) );
                    }
                }
            }
        }
    }

    // -------------------------------------------------------------------------
    // Fetch booking from DB
    // -------------------------------------------------------------------------

    public static function get_booking( $booking_id ) {
        global $wpdb;
        $table = $wpdb->prefix . 'yatoon_bookings';
        if ( is_numeric( $booking_id ) ) {
            return $wpdb->get_row( $wpdb->prepare(
                "SELECT * FROM $table WHERE id = %d LIMIT 1",
                absint( $booking_id )
            ) );
        }

        return $wpdb->get_row( $wpdb->prepare(
            "SELECT * FROM $table WHERE square_booking_id = %s LIMIT 1",
            sanitize_text_field( $booking_id )
        ) );
    }

    // -------------------------------------------------------------------------
    // Shared: replace template variables
    // -------------------------------------------------------------------------

    public static function replace_vars( $text, $booking ) {
        $start = new DateTime( $booking->start_time ?? $booking['start_time'] ?? '' );
        $end   = new DateTime( $booking->end_time   ?? $booking['end_time']   ?? '' );

        $name  = $booking->customer_name ?? $booking['customer_name'] ?? '';
        $parts = explode( ' ', $name, 2 );

        $vars = array(
            '{customer_name}'       => $name,
            '{customer_first_name}' => $parts[0],
            '{customer_email}'      => $booking->customer_email ?? $booking['customer_email'] ?? '',
            '{customer_phone}'      => $booking->customer_phone ?? $booking['customer_phone'] ?? '',
            '{service_name}'        => $booking->service_name   ?? $booking['service_name']   ?? '',
            '{staff_name}'          => $booking->staff_name     ?? $booking['staff_name']     ?? '',
            '{date}'                => $start->format( 'F j, Y' ),
            '{time}'                => $start->format( 'g:i A' ),
            '{end_time}'            => $end->format( 'g:i A' ),
            '{date_time}'           => $start->format( 'F j, Y g:i A' ),
            '{total_price}'         => number_format( (float)( $booking->total_price ?? $booking['total_price'] ?? 0 ), 2 ),
            '{notes}'               => $booking->notes ?? $booking['notes'] ?? '-',
            '{business_name}'       => get_option( 'yatoon_business_name', get_bloginfo( 'name' ) ),
            '{business_phone}'      => get_option( 'yatoon_business_phone', get_option( 'yatoon_contact_phone', '' ) ) ?: '-',
            '{business_email}'      => get_option( 'yatoon_contact_email', get_option( 'admin_email' ) ),
            '{review_link}'         => get_option( 'yatoon_review_google_link', '' ),
            '{manage_link}'         => self::get_manage_link_for_booking( $booking ),
        );

        return str_replace( array_keys( $vars ), array_values( $vars ), $text );
    }

    private static function get_manage_link_for_booking( $booking ) {
        $token = $booking->manage_token ?? $booking['manage_token'] ?? '';
        if ( empty( $token ) || ! class_exists( 'Yatoon_Manage_Booking' ) ) {
            return '';
        }

        return Yatoon_Manage_Booking::get_manage_url( $token );
    }

    // -------------------------------------------------------------------------
    // Send reminder email
    // -------------------------------------------------------------------------

    /**
     * Send confirmation email from booking data array.
     * Used by Cron sync when a Square-originated booking is detected.
     * Mirrors send_confirmation_email() in class-yatoon-ajax.php but accepts
     * a pre-built data array instead of POST data.
     *
     * @param array    $booking_data  Keys: customer_name, customer_email, start_time, end_time,
     *                                service_name, staff_name, total_price, notes, manage_token, booking_id
     * @param object   $service       Service DB row (with name, duration_minutes)
     * @param object   $staff         Staff DB row (with name)
     */
    public function send_customer_confirmation_from_data( $booking_data, $service, $staff ) {
        $to = $booking_data['customer_email'] ?? '';
        if ( empty( $to ) ) return;

        if ( get_option( 'yatoon_send_confirmation_email', '1' ) !== '1' ) return;

        $subject = get_option( 'yatoon_email_subject', 'Your appointment at {business_name} is confirmed Yes' );
        $template = get_option( 'yatoon_email_template', $this->default_confirmation_template() );

        $start = new DateTime( $booking_data['start_time'] ?? 'now' );
        $end   = new DateTime( $booking_data['end_time']   ?? 'now' );

        $name       = $booking_data['customer_name'] ?? 'Guest';
        $parts      = explode( ' ', $name, 2 );
        $staff_name = $staff ? $staff->name : 'Your technician';
        $svc_name   = $service ? $service->name : ( $booking_data['service_name'] ?? '' );
        $duration   = $service ? $service->duration_minutes : round( ( $end->getTimestamp() - $start->getTimestamp() ) / 60 );
        $biz_name   = get_option( 'yatoon_business_name', get_bloginfo( 'name' ) );
        $primary    = get_option( 'yatoon_primary_color', '#ec4899' );

        // Manage link
        $manage_link = '';
        if ( ! empty( $booking_data['manage_token'] ) && class_exists( 'Yatoon_Manage_Booking' ) ) {
            $manage_link = Yatoon_Manage_Booking::get_manage_url( $booking_data['manage_token'] );
        }

        // Calendar link
        $calendar_link = '';
        if ( ! empty( $booking_data['booking_id'] ) && ! empty( $booking_data['manage_token'] ) && class_exists( 'YATOON_Calendar_Links' ) ) {
            $calendar_link = YATOON_Calendar_Links::get_calendar_url( $booking_data['booking_id'], $booking_data['manage_token'] );
        }

        $vars = array(
            '{customer_name}'       => $name,
            '{customer_first_name}' => $parts[0],
            '{customer_email}'      => $booking_data['customer_email'] ?? '',
            '{customer_phone}'      => $booking_data['customer_phone'] ?? '',
            '{service_name}'        => $svc_name,
            '{option_names}'        => $booking_data['option_names'] ?? '',
            '{staff_name}'          => $staff_name,
            '{staff_first_name}'    => explode( ' ', $staff_name )[0],
            '{date_time}'           => $start->format( 'F j, Y g:i A' ),
            '{date}'                => $start->format( 'F j, Y' ),
            '{time}'                => $start->format( 'g:i A' ),
            '{end_time}'            => $end->format( 'g:i A' ),
            '{duration}'            => $duration,
            '{total_price}'         => number_format( (float)( $booking_data['total_price'] ?? 0 ), 2 ),
            '{notes}'               => $booking_data['notes'] ?? '',
            '{business_name}'       => $biz_name,
            '{business_phone}'      => get_option( 'yatoon_business_phone', get_option( 'yatoon_contact_phone', '' ) ) ?: '',
            '{business_email}'      => get_option( 'yatoon_contact_email', get_option( 'admin_email' ) ),
            '{manage_link}'         => $manage_link,
            '{calendar_link}'       => $calendar_link,
        );

        $subject = str_replace( array_keys( $vars ), array_values( $vars ), $subject );
        $body    = str_replace( array_keys( $vars ), array_values( $vars ), $template );

        $style = get_option( 'yatoon_email_template_style', 'plain' );
        if ( $style !== 'plain' ) {
            $body    = $this->wrap_email_html_simple( $body, $style, $primary, $biz_name );
            $headers = array( 'Content-Type: text/html; charset=UTF-8' );
        } else {
            $headers = array();
        }

        wp_mail( $to, $subject, $body, $headers );
    }

    /**
     * Simple HTML wrapper reusing the same logic as ajax class.
     */
    private function wrap_email_html_simple( $body_text, $style, $primary_color, $business_name ) {
        $logo     = get_option( 'yatoon_business_logo', '' );
        $logo_html = $logo
            ? '<img src="' . esc_url( $logo ) . '" alt="' . esc_attr( $business_name ) . '" style="height:60px;max-width:200px;object-fit:contain;display:block;margin:0 auto 16px;" />'
            : '';
        $html_body = nl2br( esc_html( $body_text ) );

        return '<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"></head>'
            . '<body style="margin:0;padding:0;background:#f4f4f5;font-family:Arial,sans-serif;">'
            . '<table width="100%" cellpadding="0" cellspacing="0" style="background:#f4f4f5;padding:40px 16px;">'
            . '<tr><td align="center"><table width="600" cellpadding="0" cellspacing="0" style="max-width:600px;width:100%;background:#fff;border-radius:12px;overflow:hidden;box-shadow:0 4px 20px rgba(0,0,0,.08);">'
            . '<tr><td style="background:' . esc_attr( $primary_color ) . ';padding:32px 40px;text-align:center;">'
            . $logo_html
            . '<h1 style="color:#fff;margin:0;font-size:24px;font-weight:700;">' . esc_html( $business_name ) . '</h1>'
            . '<p style="color:rgba(255,255,255,.85);margin:8px 0 0;font-size:15px;">Booking Confirmed Yes</p>'
            . '</td></tr>'
            . '<tr><td style="padding:40px;color:#374151;font-size:15px;line-height:1.7;">' . $html_body . '</td></tr>'
            . '<tr><td style="background:#f9fafb;padding:20px 40px;text-align:center;border-top:1px solid #e5e7eb;">'
            . '<p style="margin:0;color:#9ca3af;font-size:12px;">Powered by Yatoon Booking</p>'
            . '</td></tr>'
            . '</table></td></tr></table></body></html>';
    }

    /**
     * Default confirmation template (used when no custom template is saved)
     */
    private function default_confirmation_template() {
        return 'Hi {customer_first_name},

Your appointment has been confirmed at {business_name}!

📅 Date: {date_time}
💅 Service: {service_name} {option_names}
👤 Technician: {staff_first_name}
⏱ Duration: {duration} min
💰 Total: ${total_price}

{notes}

Need to make changes?
Cancel or reschedule here: {manage_link}

Add to your calendar: {calendar_link}

We look forward to seeing you!
{business_name}
{business_phone}';
    }

    public function send_reminder_email( $booking_id ) {
        if ( get_option( 'yatoon_reminder_enabled', '1' ) !== '1' ) return;

        $booking = $this->get_booking( $booking_id );
        if ( ! $booking || empty( $booking->customer_email ) ) return;

        // Skip if already cancelled
        if ( in_array( $booking->status ?? '', array( 'CANCELLED_BY_CUSTOMER', 'CANCELLED_BY_SELLER', 'DECLINED' ), true ) ) return;

        $subject  = $this->replace_vars( get_option( 'yatoon_reminder_subject', 'Reminder: Your appointment at {business_name} is tomorrow' ), $booking );
        $template = get_option( 'yatoon_reminder_template', $this->default_reminder_template() );
        $body     = $this->replace_vars( $template, $booking );
        $headers  = array( 'Content-Type: text/html; charset=UTF-8' );

        wp_mail( $booking->customer_email, $subject, nl2br( esc_html( $body ) ), $headers );
    }

    // -------------------------------------------------------------------------
    // Send review request email
    // -------------------------------------------------------------------------

    public function send_review_request_email( $booking_id ) {
        if ( get_option( 'yatoon_review_enabled', '1' ) !== '1' ) return;

        $booking = $this->get_booking( $booking_id );
        if ( ! $booking || empty( $booking->customer_email ) ) return;

        $subject  = $this->replace_vars( get_option( 'yatoon_review_subject', 'How was your visit to {business_name}?' ), $booking );
        $template = get_option( 'yatoon_review_template', $this->default_review_template() );
        $body     = $this->replace_vars( $template, $booking );

        // Render review button if link is set
        $review_link = get_option( 'yatoon_review_google_link', '' );
        $btn_html    = '';
        if ( $review_link ) {
            $btn_color = get_option( 'yatoon_primary_color', '#ec4899' );
            $btn_html  = '<p style="text-align:center;margin:28px 0;">
                <a href="' . esc_url( $review_link ) . '" target="_blank"
                   style="background:' . esc_attr( $btn_color ) . ';color:#fff;padding:12px 28px;
                          border-radius:6px;text-decoration:none;font-weight:600;font-size:15px;
                          display:inline-block;">* Leave a Google Review</a>
            </p>';
        }

        $html = '<div style="font-family:Arial,sans-serif;max-width:560px;margin:0 auto;padding:20px;color:#333;">'
              . nl2br( esc_html( $body ) )
              . $btn_html
              . '</div>';

        $headers = array( 'Content-Type: text/html; charset=UTF-8' );
        wp_mail( $booking->customer_email, $subject, $html, $headers );
    }

    // -------------------------------------------------------------------------
    // Default templates
    // -------------------------------------------------------------------------

    public function default_reminder_template() {
        return 'Hi {customer_first_name},

Just a friendly reminder about your upcoming appointment!

------------------------
Service:  {service_name}
Staff:    {staff_name}
Date:     {date}
Time:     {time}
------------------------

Need to reschedule or cancel? Please contact us at least 24 hours in advance:
📞 {business_phone}
✉️  {business_email}
{manage_link}

We look forward to seeing you!

- {business_name}';
    }

    public function default_review_template() {
        return 'Hi {customer_first_name},

Thank you for visiting {business_name}!

We hope you loved your {service_name} on {date}. Your feedback means the world to us and helps other clients find us.

Could you take 30 seconds to leave us a Google review? It would make our day! 🙏

Thank you so much!

- {business_name}';
    }

    // -------------------------------------------------------------------------
    // AJAX: Save settings
    // -------------------------------------------------------------------------

    public function ajax_save_settings() {
        check_ajax_referer( 'yatoon_notifications_nonce', 'nonce' );
        if ( ! current_user_can( 'manage_options' ) ) wp_send_json_error();

        $fields = array(
            'yatoon_reminder_enabled'      => 'sanitize_text_field',
            'yatoon_reminder_hours_before' => 'absint',
            'yatoon_reminder_subject'      => 'sanitize_text_field',
            'yatoon_reminder_template'     => 'sanitize_textarea_field',
            'yatoon_review_enabled'        => 'sanitize_text_field',
            'yatoon_review_hours_after'    => 'absint',
            'yatoon_review_subject'        => 'sanitize_text_field',
            'yatoon_review_template'       => 'sanitize_textarea_field',
            'yatoon_review_google_link'    => 'esc_url_raw',
            'yatoon_cancel_subject'        => 'sanitize_text_field',
            'yatoon_cancel_template'       => 'sanitize_textarea_field',
            'yatoon_reschedule_subject'    => 'sanitize_text_field',
            'yatoon_reschedule_template'   => 'sanitize_textarea_field',
            'yatoon_no_show_followup_enabled' => 'sanitize_text_field',
            'yatoon_no_show_followup_hours_after' => 'absint',
            'yatoon_no_show_followup_subject' => 'sanitize_text_field',
            'yatoon_no_show_followup_template' => 'sanitize_textarea_field',
        );

        foreach ( $fields as $key => $fn ) {
            if ( isset( $_POST[ $key ] ) ) {
                update_option( $key, $fn( wp_unslash( $_POST[ $key ] ) ) );
            } else {
                // Unchecked checkboxes won't be in POST
                if ( in_array( $key, array( 'yatoon_reminder_enabled', 'yatoon_review_enabled', 'yatoon_no_show_followup_enabled' ), true ) ) {
                    update_option( $key, '0' );
                }
            }
        }

        wp_send_json_success( array( 'message' => 'Settings saved.' ) );
    }

    // -------------------------------------------------------------------------
    // AJAX: Test emails (sends to admin email)
    // -------------------------------------------------------------------------

    public function ajax_test_reminder() {
        check_ajax_referer( 'yatoon_notifications_nonce', 'nonce' );
        if ( ! current_user_can( 'manage_options' ) ) wp_send_json_error();

        $fake = $this->fake_booking();
        $subject  = $this->replace_vars( get_option( 'yatoon_reminder_subject', 'Reminder: Your appointment at {business_name} is tomorrow' ), $fake );
        $template = get_option( 'yatoon_reminder_template', $this->default_reminder_template() );
        $body     = $this->replace_vars( $template, $fake );
        $headers  = array( 'Content-Type: text/html; charset=UTF-8' );
        $to       = get_option( 'admin_email' );

        $sent = wp_mail( $to, '[TEST] ' . $subject, nl2br( esc_html( $body ) ), $headers );
        if ( $sent ) {
            wp_send_json_success( array( 'message' => "Test reminder sent to $to" ) );
        } else {
            wp_send_json_error( array( 'message' => 'Failed to send. Check your WordPress mail settings.' ) );
        }
    }

    public function ajax_test_review() {
        check_ajax_referer( 'yatoon_notifications_nonce', 'nonce' );
        if ( ! current_user_can( 'manage_options' ) ) wp_send_json_error();

        $fake = $this->fake_booking();
        $subject  = $this->replace_vars( get_option( 'yatoon_review_subject', 'How was your visit to {business_name}?' ), $fake );
        $template = get_option( 'yatoon_review_template', $this->default_review_template() );
        $body     = $this->replace_vars( $template, $fake );

        $review_link = get_option( 'yatoon_review_google_link', '' );
        $btn_html    = '';
        if ( $review_link ) {
            $btn_color = get_option( 'yatoon_primary_color', '#ec4899' );
            $btn_html  = '<p style="text-align:center;margin:28px 0;">
                <a href="' . esc_url( $review_link ) . '" target="_blank"
                   style="background:' . esc_attr( $btn_color ) . ';color:#fff;padding:12px 28px;
                          border-radius:6px;text-decoration:none;font-weight:600;">* Leave a Google Review</a>
            </p>';
        }

        $html    = '<div style="font-family:Arial,sans-serif;max-width:560px;margin:0 auto;padding:20px;color:#333;">'
                 . nl2br( esc_html( $body ) ) . $btn_html . '</div>';
        $headers = array( 'Content-Type: text/html; charset=UTF-8' );
        $to      = get_option( 'admin_email' );

        $sent = wp_mail( $to, '[TEST] ' . $subject, $html, $headers );
        if ( $sent ) {
            wp_send_json_success( array( 'message' => "Test review request sent to $to" ) );
        } else {
            wp_send_json_error( array( 'message' => 'Failed to send. Check your WordPress mail settings.' ) );
        }
    }

    private function fake_booking() {
        $now = new DateTime( 'tomorrow 2pm' );
        $end = clone $now;
        $end->modify( '+60 minutes' );
        return (object) array(
            'booking_id'     => 'TEST-001',
            'customer_name'  => 'Jane Smith',
            'customer_email' => get_option( 'admin_email' ),
            'customer_phone' => '(317) 555-0100',
            'service_name'   => 'Gel Manicure',
            'staff_name'     => 'Lisa',
            'start_time'     => $now->format( 'Y-m-d H:i:s' ),
            'end_time'       => $end->format( 'Y-m-d H:i:s' ),
            'total_price'    => '45.00',
            'notes'          => '',
            'status'         => 'ACCEPTED',
        );
    }

    // -------------------------------------------------------------------------
    // Auto-upsert client record on every new booking
    // -------------------------------------------------------------------------

    public function upsert_client( $booking ) {
        global $wpdb;

        $phone = is_object($booking) ? ($booking->customer_phone ?? '') : ($booking['customer_phone'] ?? '');
        $email = is_object($booking) ? ($booking->customer_email ?? '') : ($booking['customer_email'] ?? '');
        $name  = is_object($booking) ? ($booking->customer_name  ?? '') : ($booking['customer_name']  ?? '');

        if ( empty($phone) && empty($email) ) return;

        $table = $wpdb->prefix . 'yatoon_clients';

        $existing = null;
        if ( $phone ) {
            $existing = $wpdb->get_row( $wpdb->prepare( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
                "SELECT id, customer_name FROM $table WHERE customer_phone = %s LIMIT 1",
                $phone
            ) );
        }
        if ( ! $existing && $email ) {
            $existing = $wpdb->get_row( $wpdb->prepare( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
                "SELECT id, customer_name FROM $table WHERE customer_email = %s LIMIT 1",
                $email
            ) );
        }

        if ( $existing ) {
            $update = array();
            if ( $name  && empty($existing->customer_name) ) $update['customer_name']  = $name;
            if ( $phone ) $update['customer_phone'] = $phone;
            if ( $email ) $update['customer_email'] = $email;
            if ( $update ) {
                $wpdb->update( $table, $update, array('id' => $existing->id) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
            }
        } else {
            $wpdb->insert( $table, array( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
                'customer_name'  => $name,
                'customer_email' => $email,
                'customer_phone' => $phone,
            ) );
        }
    }

    // -------------------------------------------------------------------------
    // Send cancellation notification email
    // -------------------------------------------------------------------------

    public function send_cancel_email( $booking ) {
        $email = is_object($booking) ? ($booking->customer_email ?? '') : ($booking['customer_email'] ?? '');
        if ( empty( $email ) ) return false;

        $subject  = $this->replace_vars( get_option( 'yatoon_cancel_subject', 'Your appointment at {business_name} has been cancelled' ), $booking );
        $template = get_option( 'yatoon_cancel_template', $this->default_cancel_template() );
        $body     = $this->replace_vars( $template, $booking );
        $headers  = array( 'Content-Type: text/html; charset=UTF-8' );
        return wp_mail( $email, $subject, nl2br( esc_html( $body ) ), $headers );
    }

    // -------------------------------------------------------------------------
    // Send reschedule notification email
    // -------------------------------------------------------------------------

    public function send_reschedule_email( $booking ) {
        $email = is_object($booking) ? ($booking->customer_email ?? '') : ($booking['customer_email'] ?? '');
        if ( empty( $email ) ) return false;

        $subject  = $this->replace_vars( get_option( 'yatoon_reschedule_subject', 'Your appointment at {business_name} has been rescheduled' ), $booking );
        $template = get_option( 'yatoon_reschedule_template', $this->default_reschedule_template() );
        $body     = $this->replace_vars( $template, $booking );
        $headers  = array( 'Content-Type: text/html; charset=UTF-8' );
        return wp_mail( $email, $subject, nl2br( esc_html( $body ) ), $headers );
    }

    // -------------------------------------------------------------------------
    // Default templates
    // -------------------------------------------------------------------------

    public function default_cancel_template() {
        return 'Hi {customer_first_name},

We wanted to let you know that your appointment has been cancelled.

------------------------
Service:  {service_name}
Staff:    {staff_name}
Date:     {date}
Time:     {time}
------------------------

If you have any questions or would like to rebook, please contact us:
📞 {business_phone}
✉️  {business_email}

We hope to see you again soon!

- {business_name}';
    }

    public function default_reschedule_template() {
        return 'Hi {customer_first_name},

Your appointment has been rescheduled. Here are your updated details:

------------------------
Service:  {service_name}
Staff:    {staff_name}
New Date: {date}
New Time: {time}
------------------------

If this doesn\'t look right or you need to make further changes, please contact us:
📞 {business_phone}
✉️  {business_email}

We look forward to seeing you!

- {business_name}';
    }

    public function schedule_no_show_followup( $booking_id ) {
        if ( get_option( 'yatoon_no_show_followup_enabled', '1' ) !== '1' ) return;

        $hours_after = max( 0, intval( get_option( 'yatoon_no_show_followup_hours_after', 1 ) ) );
        $send_ts = time() + ( $hours_after * HOUR_IN_SECONDS );

        if ( ! wp_next_scheduled( 'yatoon_send_no_show_followup', array( $booking_id ) ) ) {
            wp_schedule_single_event( $send_ts, 'yatoon_send_no_show_followup', array( $booking_id ) );
        }
    }

    public function send_no_show_followup_email( $booking_id ) {
        if ( get_option( 'yatoon_no_show_followup_enabled', '1' ) !== '1' ) return false;

        $booking = $this->get_booking( $booking_id );
        if ( ! $booking || empty( $booking->customer_email ) ) return false;
        if ( ! in_array( $booking->status ?? '', array( 'no_show', 'NO_SHOW' ), true ) ) return false;

        $subject  = $this->replace_vars( get_option( 'yatoon_no_show_followup_subject', 'We missed you at {business_name}' ), $booking );
        $template = get_option( 'yatoon_no_show_followup_template', $this->default_no_show_followup_template() );
        $body     = $this->replace_vars( $template, $booking );
        $headers  = array( 'Content-Type: text/html; charset=UTF-8' );
        return wp_mail( $booking->customer_email, $subject, nl2br( esc_html( $body ) ), $headers );
    }

    public function default_no_show_followup_template() {
        return 'Hi {customer_first_name},

We missed you for your appointment at {business_name}.

------------------------
Service:  {service_name}
Date:     {date}
Time:     {time}
------------------------

If something came up, no worries. You can contact us to rebook:
📞 {business_phone}
✉️  {business_email}

If your appointment required a deposit or had a cancellation policy, our team can help explain the next step.

- {business_name}';
    }

    // -------------------------------------------------------------------------
    // AJAX: Test cancel / reschedule emails
    // -------------------------------------------------------------------------

    public function ajax_test_cancel_email() {
        check_ajax_referer( 'yatoon_notifications_nonce', 'nonce' );
        if ( ! current_user_can( 'manage_options' ) ) wp_send_json_error();
        $fake = $this->fake_booking();
        $sent = $this->send_cancel_email( $fake );
        $to   = get_option( 'admin_email' );
        if ( $sent ) wp_send_json_success( array( 'message' => "Test cancel email sent to $to" ) );
        else         wp_send_json_error(   array( 'message' => 'Failed to send. Check WordPress mail settings.' ) );
    }

    public function ajax_test_reschedule_email() {
        check_ajax_referer( 'yatoon_notifications_nonce', 'nonce' );
        if ( ! current_user_can( 'manage_options' ) ) wp_send_json_error();
        $fake = $this->fake_booking();
        $sent = $this->send_reschedule_email( $fake );
        $to   = get_option( 'admin_email' );
        if ( $sent ) wp_send_json_success( array( 'message' => "Test reschedule email sent to $to" ) );
        else         wp_send_json_error(   array( 'message' => 'Failed to send. Check WordPress mail settings.' ) );
    }

    public function ajax_test_no_show_email() {
        check_ajax_referer( 'yatoon_notifications_nonce', 'nonce' );
        if ( ! current_user_can( 'manage_options' ) ) wp_send_json_error();
        $fake = $this->fake_booking();
        $fake->status = 'no_show';
        $subject  = $this->replace_vars( get_option( 'yatoon_no_show_followup_subject', 'We missed you at {business_name}' ), $fake );
        $template = get_option( 'yatoon_no_show_followup_template', $this->default_no_show_followup_template() );
        $body     = $this->replace_vars( $template, $fake );
        $to       = get_option( 'admin_email' );
        $sent     = wp_mail( $to, '[TEST] ' . $subject, nl2br( esc_html( $body ) ), array( 'Content-Type: text/html; charset=UTF-8' ) );
        if ( $sent ) wp_send_json_success( array( 'message' => "Test no-show follow-up sent to $to" ) );
        else         wp_send_json_error(   array( 'message' => 'Failed to send. Check WordPress mail settings.' ) );
    }
}
