<?php
// 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_Recurring  (Pro only)
 *
 * After a booking is confirmed, if the customer opted in to a recurring series,
 * this class creates future bookings at the chosen weekly interval.
 *
 * Flow:
 *  1. Frontend JS shows "Make this recurring?" after booking confirmed (success page)
 *  2. Customer picks frequency (1/2/3/4 weeks) and submits via AJAX
 *  3. This class creates N future bookings and records them in yatoon_recurring
 *  4. Customer can cancel the whole series via manage-booking page
 *  5. Admin can see all series in the Recurring admin view
 */
class YATOON_Recurring {

    public function __construct() {
        // AJAX: set up recurring series from success page
        add_action('wp_ajax_yatoon_setup_recurring',        array($this, 'ajax_setup_recurring'));
        add_action('wp_ajax_nopriv_yatoon_setup_recurring', array($this, 'ajax_setup_recurring'));

        // AJAX: cancel series
        add_action('wp_ajax_yatoon_cancel_recurring_series',        array($this, 'ajax_cancel_series'));
        add_action('wp_ajax_nopriv_yatoon_cancel_recurring_series', array($this, 'ajax_cancel_series'));

        // Hook: when a booking is cancelled, check if it's part of a series
        add_action('yatoon_booking_cancelled', array($this, 'handle_booking_cancelled'), 10, 1);
    }

    // -------------------------------------------------------------------------
    // AJAX: Customer sets up recurring from success page
    // -------------------------------------------------------------------------

    public function ajax_setup_recurring() {
        check_ajax_referer('yatoon_frontend_nonce', 'nonce');

        if (!class_exists('YATOON_License') || !YATOON_License::is_pro()) {
            wp_send_json_error(array('message' => 'Recurring appointments require Pro.'));
        }

        $booking_id      = absint($_POST['booking_id'] ?? 0);
        $manage_token    = sanitize_text_field(wp_unslash($_POST['manage_token'] ?? ''));
        $frequency_weeks = min(4, max(1, intval($_POST['frequency_weeks'] ?? 2)));
        $total_count     = min(12, max(2, intval($_POST['total_count'] ?? 6)));

        if (!$booking_id || !$manage_token) {
            wp_send_json_error(array('message' => 'Invalid booking reference.'));
        }

        global $wpdb;
        $bookings_table  = $wpdb->prefix . 'yatoon_bookings';
        $recurring_table = $wpdb->prefix . 'yatoon_recurring';

        // Verify token
        $booking = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM $bookings_table WHERE id = %d AND manage_token = %s LIMIT 1",
            $booking_id, $manage_token
        ));

        if (!$booking) {
            wp_send_json_error(array('message' => 'Booking not found.'));
        }

        // Don't duplicate series
        $existing_series = $wpdb->get_var($wpdb->prepare(
            "SELECT series_id FROM $recurring_table WHERE booking_id = %d LIMIT 1", $booking_id
        ));
        if ($existing_series) {
            wp_send_json_success(array('series_id' => $existing_series, 'created' => 0, 'message' => 'Series already exists.'));
        }

        $series_id = wp_generate_password(16, false);

        // Record this booking as occurrence #1
        $wpdb->insert($recurring_table, array(
            'series_id'       => $series_id,
            'booking_id'      => $booking_id,
            'customer_name'   => $booking->customer_name,
            'customer_email'  => $booking->customer_email,
            'customer_phone'  => $booking->customer_phone,
            'service_id'      => $booking->service_id,
            'staff_id'        => $booking->staff_id,
            'frequency_weeks' => $frequency_weeks,
            'total_count'     => $total_count,
            'occurrence_num'  => 1,
            'status'          => 'active',
        ));

        // Calculate duration
        $start_ts  = strtotime($booking->start_time);
        $end_ts    = strtotime($booking->end_time);
        $duration  = $end_ts - $start_ts; // seconds

        $created = 0;
        $failed  = 0;

        for ($i = 2; $i <= $total_count; $i++) {
            $weeks_offset = ($i - 1) * $frequency_weeks;
            $new_start_ts = strtotime("+{$weeks_offset} weeks", $start_ts);
            $new_end_ts   = $new_start_ts + $duration;

            $new_start = gmdate('Y-m-d H:i:s', $new_start_ts);
            $new_end   = gmdate('Y-m-d H:i:s', $new_end_ts);

            // Check basic availability (no existing booking for same staff/time)
            $conflict = $wpdb->get_var($wpdb->prepare(
                "SELECT id FROM $bookings_table
                 WHERE staff_id = %d
                   AND status NOT IN ('cancelled','CANCELLED_BY_CUSTOMER','CANCELLED_BY_SELLER','DECLINED','no_show')
                   AND start_time < %s AND end_time > %s
                 LIMIT 1",
                $booking->staff_id, $new_end, $new_start
            ));

            if ($conflict) {
                $failed++;
                continue;
            }

            // Create the booking
            $manage_token_new = wp_generate_password(32, false);
            $wpdb->insert($bookings_table, array(
                'service_id'    => $booking->service_id,
                'staff_id'      => $booking->staff_id,
                'customer_name' => $booking->customer_name,
                'customer_email'=> $booking->customer_email,
                'customer_phone'=> $booking->customer_phone,
                'start_time'    => $new_start,
                'end_time'      => $new_end,
                'total_price'   => $booking->total_price,
                'status'        => 'confirmed',
                'payment_status'=> 'unpaid',
                'notes'         => 'Recurring series - every ' . $frequency_weeks . ' week(s).',
                'manage_token'  => $manage_token_new,
            ));

            $new_booking_id = $wpdb->insert_id;

            // Record in recurring table
            $wpdb->insert($recurring_table, array(
                'series_id'       => $series_id,
                'booking_id'      => $new_booking_id,
                'customer_name'   => $booking->customer_name,
                'customer_email'  => $booking->customer_email,
                'customer_phone'  => $booking->customer_phone,
                'service_id'      => $booking->service_id,
                'staff_id'        => $booking->staff_id,
                'frequency_weeks' => $frequency_weeks,
                'total_count'     => $total_count,
                'occurrence_num'  => $i,
                'status'          => 'active',
            ));

            // Fire booking created hook for notifications
            do_action('yatoon_booking_created', array(
                'booking_id'    => $new_booking_id,
                'customer_name' => $booking->customer_name,
                'customer_email'=> $booking->customer_email,
                'customer_phone'=> $booking->customer_phone,
                'start_time'    => $new_start,
                'end_time'      => $new_end,
                'service_name'  => '',
                'staff_name'    => '',
                'total_price'   => $booking->total_price,
                'manage_token'  => $manage_token_new,
                'notes'         => '',
            ));

            $created++;
        }

        wp_send_json_success(array(
            'series_id' => $series_id,
            'created'   => $created,
            'failed'    => $failed,
            'message'   => $created . ' future appointment' . ($created !== 1 ? 's' : '') . ' scheduled!'
                         . ($failed ? ' ' . $failed . ' slot(s) were unavailable and skipped.' : ''),
        ));
    }

    // -------------------------------------------------------------------------
    // AJAX: Cancel entire series
    // -------------------------------------------------------------------------

    public function ajax_cancel_series() {
        check_ajax_referer('yatoon_frontend_nonce', 'nonce');

        $series_id    = sanitize_text_field(wp_unslash($_POST['series_id'] ?? ''));
        $manage_token = sanitize_text_field(wp_unslash($_POST['manage_token'] ?? ''));

        if (!$series_id || !$manage_token) {
            wp_send_json_error(array('message' => 'Missing parameters.'));
        }

        global $wpdb;
        $bookings_table  = $wpdb->prefix . 'yatoon_bookings';
        $recurring_table = $wpdb->prefix . 'yatoon_recurring';

        // Verify the token belongs to a booking in this series
        $valid = $wpdb->get_var($wpdb->prepare(
            "SELECT r.id FROM $recurring_table r
             JOIN $bookings_table b ON b.id = r.booking_id
             WHERE r.series_id = %s AND b.manage_token = %s LIMIT 1",
            $series_id, $manage_token
        ));

        if (!$valid) {
            wp_send_json_error(array('message' => 'Invalid series or token.'));
        }

        // Get all future booking IDs in series
        $now    = current_time('mysql');
        $future = $wpdb->get_col($wpdb->prepare(
            "SELECT r.booking_id FROM $recurring_table r
             JOIN $bookings_table b ON b.id = r.booking_id
             WHERE r.series_id = %s AND r.status = 'active' AND b.start_time > %s",
            $series_id, $now
        ));

        foreach ($future as $bid) {
            $wpdb->update($bookings_table,
                array('status' => 'CANCELLED_BY_CUSTOMER'),
                array('id' => absint($bid))
            );
            $wpdb->update($recurring_table,
                array('status' => 'cancelled', 'cancelled_at' => $now),
                array('booking_id' => absint($bid))
            );
        }

        wp_send_json_success(array(
            'cancelled' => count($future),
            'message'   => count($future) . ' future appointment' . (count($future) !== 1 ? 's' : '') . ' cancelled.',
        ));
    }

    // -------------------------------------------------------------------------
    // Hook: booking cancelled - mark recurring entry
    // -------------------------------------------------------------------------

    public function handle_booking_cancelled($booking_id) {
        global $wpdb;
        $wpdb->update(
            $wpdb->prefix . 'yatoon_recurring',
            array('status' => 'cancelled', 'cancelled_at' => current_time('mysql')),
            array('booking_id' => absint($booking_id))
        );
    }
}
