<?php
/**
 * Wizard REST Controller
 *
 * @package WahraRentalsBookings
 */

defined('ABSPATH') || exit;

/**
 * Wizard controller class
 */
class WAHRB_Wizard_Controller extends WAHRB_REST_Controller {

    /**
     * Route base
     *
     * @var string
     */
    protected $rest_base = 'vendor/wizard';

    /**
     * Register routes
     */
    public function register_routes(): void {
        // Get drafted
        register_rest_route($this->namespace, '/' . $this->rest_base . '/drafts', [
            [
                'methods' => WP_REST_Server::READABLE,
                'callback' => [$this, 'get_drafts'],
                'permission_callback' => [$this, 'check_vendor_permission'],
            ],
        ]);

        // Get or create draft
        register_rest_route($this->namespace, '/' . $this->rest_base . '/draft', [
            [
                'methods' => WP_REST_Server::READABLE,
                'callback' => [$this, 'get_draft'],
                'permission_callback' => [$this, 'check_vendor_permission'],
                'args' => [
                    'product_id' => [
                        'type' => 'integer',
                        'default' => 0,
                    ],
                ],
            ],
            [
                'methods' => WP_REST_Server::CREATABLE,
                'callback' => [$this, 'save_draft'],
                'permission_callback' => [$this, 'check_vendor_permission'],
                'args' => $this->get_draft_args(),
            ],
        ]);

        // Delete draft
        register_rest_route($this->namespace, '/' . $this->rest_base . '/draft/(?P<id>\d+)', [
            [
                'methods' => WP_REST_Server::DELETABLE,
                'callback' => [$this, 'delete_draft'],
                'permission_callback' => [$this, 'check_vendor_permission'],
            ],
        ]);

        // Publish offer
        register_rest_route($this->namespace, '/' . $this->rest_base . '/publish', [
            [
                'methods' => WP_REST_Server::CREATABLE,
                'callback' => [$this, 'publish'],
                'permission_callback' => [$this, 'check_vendor_permission'],
                'args' => [
                    'draft_id' => [
                        'type' => 'integer',
                        'required' => true,
                    ],
                ],
            ],
        ]);

        // Get vendor products
        register_rest_route($this->namespace, '/' . $this->rest_base . '/products', [
            [
                'methods' => WP_REST_Server::READABLE,
                'callback' => [$this, 'get_products'],
                'permission_callback' => [$this, 'check_vendor_permission'],
                'args' => [
                    'search' => [
                        'type' => 'string',
                        'default' => '',
                    ],
                    'rental_only' => [
                        'type' => 'boolean',
                        'default' => false,
                    ],
                ],
            ],
        ]);

        // Calculate price preview
        register_rest_route($this->namespace, '/' . $this->rest_base . '/price-preview', [
            [
                'methods' => WP_REST_Server::CREATABLE,
                'callback' => [$this, 'price_preview'],
                'permission_callback' => [$this, 'check_vendor_permission'],
                'args' => [
                    'base_price' => [
                        'type' => 'number',
                        'required' => true,
                    ],
                    'rules' => [
                        'type' => 'array',
                        'default' => [],
                    ],
                    'start_date' => [
                        'type' => 'string',
                        'required' => true,
                    ],
                    'end_date' => [
                        'type' => 'string',
                        'required' => true,
                    ],
                    'qty' => [
                        'type' => 'integer',
                        'default' => 1,
                    ],
                ],
            ],
        ]);

        // Upload image
        register_rest_route($this->namespace, '/' . $this->rest_base . '/upload', [
            [
                'methods' => WP_REST_Server::CREATABLE,
                'callback' => [$this, 'upload_image'],
                'permission_callback' => [$this, 'check_vendor_permission'],
            ],
        ]);

        // Get settings (default values)
        register_rest_route($this->namespace, '/' . $this->rest_base . '/settings', [
            [
                'methods' => WP_REST_Server::READABLE,
                'callback' => [$this, 'get_settings'],
                'permission_callback' => [$this, 'check_vendor_permission'],
            ],
        ]);
    }

    /**
     * Get draft args
     *
     * @return array
     */
    private function get_draft_args(): array {
        return [
            'draft_id' => [
                'type' => 'integer',
                'default' => 0,
            ],
            'product_id' => [
                'type' => 'integer',
                'default' => 0,
            ],
            'current_step' => [
                'type' => 'integer',
                'required' => true,
                'minimum' => 0,
                'maximum' => 7,
            ],
            'step_data' => [
                'type' => 'object',
                'required' => true,
            ],
        ];
    }

    /**
     * Get draft
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response|WP_Error
     */
    public function get_draft($request) {
        $vendor_id = $this->get_vendor_id();
        $product_id = absint($request->get_param('product_id'));
        $draft_id = absint($request->get_param('draft_id')); // Support getting by ID

        global $wpdb;
        $db = WAHRB_Database::instance();

        if ($draft_id) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
            $draft = $wpdb->get_row($wpdb->prepare(
                "SELECT * FROM {$db->table('wizard_drafts')}
                 WHERE draft_id = %d AND vendor_id = %d",
                $draft_id, $vendor_id
            ), ARRAY_A);
        } elseif ($product_id) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
            $draft = $wpdb->get_row($wpdb->prepare(
                "SELECT * FROM {$db->table('wizard_drafts')}
                 WHERE vendor_id = %d AND product_id = %d
                 ORDER BY updated_at DESC LIMIT 1",
                $vendor_id, $product_id
            ), ARRAY_A);
        } else {
            // Get most recent incomplete draft (use is_complete for backward compat)
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
            $draft = $wpdb->get_row($wpdb->prepare(
                "SELECT * FROM {$db->table('wizard_drafts')}
                 WHERE vendor_id = %d AND is_complete = 0
                 ORDER BY updated_at DESC LIMIT 1",
                $vendor_id
            ), ARRAY_A);
        }

        // If no draft exists but a product_id was provided, create a draft with product data
        if (!$draft && $product_id) {
            $product = wc_get_product($product_id);
            if ($product && (int)get_post_field('post_author', $product_id) === $vendor_id) {
                // Extract existing product data into wizard format
                $wizard_data = $this->extract_wizard_data_from_product($product_id);
                
                // Create a new draft with this data
                $new_hash = wp_generate_password(32, false);
                $offer_type = get_post_meta($product_id, '_wahrb_booking_mode', true) ?: 'day';
                
                $insert_data = [
                    'vendor_id' => $vendor_id,
                    'product_id' => $product_id,
                    'offer_type' => $offer_type,
                    'current_step' => 1,
                    'wizard_data' => wp_json_encode($wizard_data),
                    'status' => 'in_progress',
                    'is_complete' => 0,
                    'version_hash' => $new_hash,
                    'created_at' => current_time('mysql'),
                    'updated_at' => current_time('mysql'),
                ];
                
                // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
                $wpdb->insert($db->table('wizard_drafts'), $insert_data);
                $new_draft_id = $wpdb->insert_id;
                
                if ($new_draft_id) {
                    return $this->success([
                        'draft' => [
                            'draft_id' => $new_draft_id,
                            'product_id' => $product_id,
                            'vendor_id' => $vendor_id,
                            'offer_type' => $offer_type,
                            'current_step' => 1,
                            'wizard_data' => $wizard_data,
                            'version_hash' => $new_hash,
                            'is_editing_product' => true,
                        ],
                    ]);
                }
            }
        }
        
        if (!$draft) {
            return $this->success([
                'draft' => null,
                'message' => __('No draft found.', 'wahra-rentals-bookings'),
            ]);
        }

        $draft['wizard_data'] = json_decode($draft['wizard_data'], true);

        return $this->success([
            'draft' => $draft,
        ]);
    }
    
    /**
     * Extract wizard data from existing product
     *
     * @param int $product_id Product ID
     * @return array Wizard data structure
     */
    private function extract_wizard_data_from_product(int $product_id): array {
        $product = wc_get_product($product_id);
        if (!$product) {
            return [];
        }
        
        $offer_type = get_post_meta($product_id, '_wahrb_booking_mode', true) ?: 'day';
        
        $wizard_data = [
            // Step 1: Offer Type
            'step_1' => [
                'offer_type' => $offer_type,
            ],
            // Step 2: Product/Inventory
            'step_2' => [
                'use_existing' => true,
                'product_id' => $product_id,
                'product_name' => $product->get_name(),
                'product_description' => $product->get_description(),
                'total_units' => absint(get_post_meta($product_id, '_wahrb_total_units', true)) ?: 1,
            ],
            // Step 3: Availability
            'step_3' => [
                'recurring_days' => get_post_meta($product_id, '_wahrb_recurring_days', true) ?: ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'],
                'recurring_hours' => get_post_meta($product_id, '_wahrb_recurring_hours', true) ?: [],
                'min_duration' => absint(get_post_meta($product_id, '_wahrb_min_duration', true)) ?: 1,
                'max_duration' => absint(get_post_meta($product_id, '_wahrb_max_duration', true)) ?: 30,
                'min_booking_window' => absint(get_post_meta($product_id, '_wahrb_min_booking_window', true)) ?: 24,
                'max_booking_window' => absint(get_post_meta($product_id, '_wahrb_max_booking_window', true)) ?: 365,
                'buffer_before' => absint(get_post_meta($product_id, '_wahrb_buffer_before', true)) ?: 0,
                'buffer_after' => absint(get_post_meta($product_id, '_wahrb_buffer_after', true)) ?: 0,
            ],
            // Step 4: Pricing
            'step_4' => [
                'base_price' => floatval(get_post_meta($product_id, '_wahrb_base_price', true)) ?: floatval($product->get_price()),
                'price_unit' => get_post_meta($product_id, '_wahrb_price_unit', true) ?: 'day',
                'rules' => [],
            ],
            // Step 5: Payment
            'step_5' => [
                'deposit_enabled' => get_post_meta($product_id, '_wahrb_deposit_enabled', true) === 'yes',
                'deposit_type' => get_post_meta($product_id, '_wahrb_deposit_type', true) ?: 'percent',
                'deposit_value' => floatval(get_post_meta($product_id, '_wahrb_deposit_value', true)) ?: 30,
                'deposit_refundable' => get_post_meta($product_id, '_wahrb_deposit_refundable', true) === 'yes',
                'security_enabled' => get_post_meta($product_id, '_wahrb_security_deposit_enabled', true) === 'yes',
                'security_amount' => floatval(get_post_meta($product_id, '_wahrb_security_deposit', true)) ?: 0,
                'security_mode' => get_post_meta($product_id, '_wahrb_security_mode', true) ?: 'capture',
                'balance_enabled' => get_post_meta($product_id, '_wahrb_balance_enabled', true) === 'yes',
                'balance_due_days' => absint(get_post_meta($product_id, '_wahrb_balance_due_days', true)) ?: 3,
                'balance_allow_cod' => get_post_meta($product_id, '_wahrb_balance_allow_cod', true) === 'yes',
            ],
            // Step 6 (photos) removed - handled at product level
            // Step 7: Publish settings (now step 6 in UI)
            'step_7' => [
                'cancellation_policy' => get_post_meta($product_id, '_wahrb_cancellation_policy', true) ?: 'flexible',
                'terms_accepted' => false,
            ],
            'last_step' => 1,
        ];
        
        return $wizard_data;
    }
    
    /**
     * Get product images for wizard
     *
     * @param int $product_id Product ID
     * @return array Images array
     */
    private function get_product_images(int $product_id): array {
        $images = [];
        $product = wc_get_product($product_id);
        
        if (!$product) {
            return $images;
        }
        
        // Get featured image
        $featured_id = $product->get_image_id();
        if ($featured_id) {
            $images[] = [
                'id' => $featured_id,
                'url' => wp_get_attachment_url($featured_id),
                'thumbnail' => wp_get_attachment_image_url($featured_id, 'thumbnail'),
            ];
        }
        
        // Get gallery images
        $gallery_ids = $product->get_gallery_image_ids();
        foreach ($gallery_ids as $img_id) {
            $images[] = [
                'id' => $img_id,
                'url' => wp_get_attachment_url($img_id),
                'thumbnail' => wp_get_attachment_image_url($img_id, 'thumbnail'),
            ];
        }
        
        return $images;
    }

    /**
     * Get all drafts for vendor
     * 
     * @param WP_REST_Request $request
     * @return WP_REST_Response
     */
    public function get_drafts($request) {
        $vendor_id = $this->get_vendor_id();
        global $wpdb;
        $db = WAHRB_Database::instance();

        // Get drafts that are not complete and whose product is NOT published
        // This excludes drafts for products that have been successfully published
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        $drafts = $wpdb->get_results($wpdb->prepare(
            "SELECT d.draft_id, d.product_id, d.current_step, d.updated_at, d.wizard_data 
             FROM {$db->table('wizard_drafts')} d
             LEFT JOIN {$wpdb->posts} p ON d.product_id = p.ID
             WHERE d.vendor_id = %d 
               AND d.is_complete = 0
               AND (d.product_id IS NULL OR d.product_id = 0 OR p.post_status != 'publish')
             ORDER BY d.updated_at DESC",
            $vendor_id
        ), ARRAY_A);

        // Process drafts to add easy to read info
        foreach ($drafts as &$draft) {
            $data = json_decode($draft['wizard_data'], true);
            
            // Get product name - check wizard data first, then product if available
            $product_name = $data['step_2']['product_name'] ?? '';
            if (empty($product_name) && !empty($draft['product_id'])) {
                $product = wc_get_product($draft['product_id']);
                if ($product) {
                    $product_name = $product->get_name();
                }
            }
            $draft['product_name'] = $product_name ?: __('Nouvel article', 'wahra-rentals-bookings');
            $draft['offer_type'] = $data['step_1']['offer_type'] ?? 'day';
            $draft['platform_category'] = $data['step_1']['platform_category'] ?? '';
            unset($draft['wizard_data']); // Remove heavy data from list
        }

        return $this->success($drafts);
    }

    /**
     * Save draft
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response|WP_Error
     */
    public function save_draft($request) {
        $vendor_id = $this->get_vendor_id();
        $draft_id = absint($request->get_param('draft_id'));
        $product_id_raw = $request->get_param('product_id');
        // Use 0 for no product (NULL can cause issues with some wpdb/MySQL configs)
        $product_id = !empty($product_id_raw) ? absint($product_id_raw) : 0;
        $current_step = absint($request->get_param('current_step'));
        // Clamp to valid wizard step range (1-6)
        if ($current_step < 1) {
            $current_step = 1;
        } elseif ($current_step > 6) {
            $current_step = 6;
        }
        $step_data = $request->get_param('step_data');

        global $wpdb;
        $db = WAHRB_Database::instance();

        $version_hash = sanitize_text_field($request->get_param('version_hash'));

        // Sanitize step data recursively
        $step_data = $this->sanitize_recursive($step_data);

        // Get existing draft or create new
        if ($draft_id) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
            $existing = $wpdb->get_row($wpdb->prepare(
                "SELECT * FROM {$db->table('wizard_drafts')} WHERE draft_id = %d AND vendor_id = %d",
                $draft_id, $vendor_id
            ), ARRAY_A);

            if (!$existing) {
                return $this->error('draft_not_found', __('Draft not found.', 'wahra-rentals-bookings'), 404);
            }

            // OPTIMISTIC LOCKING: Check if version hash matches
            if (!empty($existing['version_hash']) && $existing['version_hash'] !== $version_hash) {
                return $this->error('conflict', __('Version conflict: This draft was modified elsewhere. Please refresh.', 'wahra-rentals-bookings'), 409);
            }

            $wizard_data = json_decode($existing['wizard_data'], true) ?: [];
        } else {
            // Check if a draft already exists for this product_id (enforce uniqueness)
            if ($product_id) {
                // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
                $existing_for_product = $wpdb->get_row($wpdb->prepare(
                    "SELECT * FROM {$db->table('wizard_drafts')} 
                     WHERE vendor_id = %d AND product_id = %d AND status = 'in_progress'",
                    $vendor_id, $product_id
                ), ARRAY_A);
                
                if ($existing_for_product) {
                    // Reuse existing draft for this product
                    $draft_id = $existing_for_product['draft_id'];
                    $wizard_data = json_decode($existing_for_product['wizard_data'], true) ?: [];
                    $version_hash = $existing_for_product['version_hash'];
                    $existing = $existing_for_product;
                }
            }
            
            // If no existing draft found, check limit and create new
            if (!isset($existing)) {
                // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
                $count = $wpdb->get_var($wpdb->prepare(
                    "SELECT COUNT(*) FROM {$db->table('wizard_drafts')} 
                     WHERE vendor_id = %d AND status = 'in_progress'",
                    $vendor_id
                ));

                if ($count >= 3) {
                    return $this->error('draft_limit_reached', __('You have reached the 3-draft limit. Please finish or delete one.', 'wahra-rentals-bookings'), 400);
                }

                $wizard_data = [];
            }
        }

        // Merge step data
        // NOTE: Validation is handled client-side via wizard-validation.js to reduce server load
        $wizard_data['step_' . $current_step] = $step_data;
        $wizard_data['last_step'] = $current_step;

        // Track the highest step ever saved — used by the PHP template to enforce
        // sequential progression and prevent skipping to a future step via URL manipulation.
        $wizard_data['max_step'] = max($current_step, absint($wizard_data['max_step'] ?? 0));

        // Determine offer type from step 1 (platform_category is primary, offer_type is fallback)
        $step1 = $wizard_data['step_1'] ?? [];
        $platform_category = $step1['platform_category'] ?? '';
        $offer_type = $step1['offer_type'] ?? 'day';

        // Auto-resolve offer_type from platform_category if available
        if (!empty($platform_category) && class_exists('WAHRB_Platform_Categories')) {
            $modes = WAHRB_Platform_Categories::get_booking_modes($platform_category);
            if (!empty($modes)) {
                $offer_type = $modes[0];
            }
        }

        // Generate new hash
        $new_hash = wp_generate_password(32, false);

        $data = [
            'vendor_id' => $vendor_id,
            'product_id' => $product_id,
            'offer_type' => $offer_type,
            'current_step' => $current_step,
            'wizard_data' => wp_json_encode($wizard_data),
            'status' => 'in_progress',
            'version_hash' => $new_hash,
            'updated_at' => current_time('mysql'),
        ];

        if ($draft_id && $existing) {
            // Update existing
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
            $result = $wpdb->update(
                $db->table('wizard_drafts'),
                $data,
                ['draft_id' => $draft_id]
            );
            if (false === $result) {
                error_log('WAHRB Wizard update failed for draft ' . $draft_id . ': ' . $wpdb->last_error);
                return $this->error('save_failed', __('Error while saving.', 'wahra-rentals-bookings') . ' ' . $wpdb->last_error, 500);
            }
        } else {
            // Create new
            $data['created_at'] = current_time('mysql');
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
            $result = $wpdb->insert($db->table('wizard_drafts'), $data);
            if (false === $result) {
                error_log('WAHRB Wizard insert failed: ' . $wpdb->last_error . ' | Data: ' . wp_json_encode(array_keys($data)));
                return $this->error('save_failed', __('Error while saving.', 'wahra-rentals-bookings') . ' DB: ' . $wpdb->last_error, 500);
            }
            $draft_id = $wpdb->insert_id;
        }

        if (!$draft_id) {
            error_log('WAHRB Wizard save_draft: insert_id is 0 after insert. Last error: ' . $wpdb->last_error);
            return $this->error('save_failed', __('Error while saving.', 'wahra-rentals-bookings') . ' ' . $wpdb->last_error, 500);
        }

        return $this->success([
            'draft_id' => $draft_id,
            'current_step' => $current_step,
            'version_hash' => $new_hash,
            'message' => __('Draft saved.', 'wahra-rentals-bookings'),
        ]);
    }

    /**
     * Delete draft
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response|WP_Error
     */
    public function delete_draft($request) {
        $draft_id = absint($request->get_param('id'));
        $vendor_id = $this->get_vendor_id();

        global $wpdb;
        $db = WAHRB_Database::instance();

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $deleted = $wpdb->delete(
            $db->table('wizard_drafts'),
            [
                'draft_id' => $draft_id,
                'vendor_id' => $vendor_id,
            ]
        );

        if (!$deleted) {
            return $this->error('delete_failed', __('Draft not found.', 'wahra-rentals-bookings'), 404);
        }

        return $this->success([
            'message' => __('Draft deleted.', 'wahra-rentals-bookings'),
        ]);
    }

    /**
     * Publish offer
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response|WP_Error
     */
    public function publish($request) {
        $draft_id = absint($request->get_param('draft_id'));
        $vendor_id = $this->get_vendor_id();

        global $wpdb;
        $db = WAHRB_Database::instance();

        // Get draft
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        $draft = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM {$db->table('wizard_drafts')} WHERE draft_id = %d AND vendor_id = %d",
            $draft_id, $vendor_id
        ), ARRAY_A);

        if (!$draft) {
            return $this->error('draft_not_found', __('Draft not found.', 'wahra-rentals-bookings'), 404);
        }

        $wizard_data = json_decode($draft['wizard_data'], true);

        // Validate required steps
        $required_steps = ['step_1', 'step_2', 'step_3', 'step_4', 'step_5'];
        $step_names = [
            'step_1' => __('Offer Type', 'wahra-rentals-bookings'),
            'step_2' => __('Product', 'wahra-rentals-bookings'),
            'step_3' => __('Availability', 'wahra-rentals-bookings'),
            'step_4' => __('Pricing', 'wahra-rentals-bookings'),
            'step_5' => __('Payment', 'wahra-rentals-bookings'),
        ];
        foreach ($required_steps as $step) {
            if (empty($wizard_data[$step])) {
                /* translators: %s: wizard step name (e.g., "Availability", "Pricing") */
                return $this->error('incomplete', sprintf(__('Step "%s" is incomplete.', 'wahra-rentals-bookings'), $step_names[$step]));
            }
        }

        // Create or update product
        $product_id = $draft['product_id'];
        $step2 = $wizard_data['step_2'];
        $is_new_product = false;

        // Logic fix: Check if we need to create a new product based on 'use_existing' flag
        // If product_id is empty OR use_existing is explicitly false, we create
        if (!$product_id || (isset($step2['use_existing']) && !$step2['use_existing'])) {
            // Create new product
            $product = new WC_Product_Simple();
            $product->set_name(sanitize_text_field($step2['product_name']));
            $product->set_description(wp_kses_post($step2['product_description'] ?? ''));
            $product->set_status('publish');
            $product->set_catalog_visibility('visible');
            $product->save();
            $product_id = $product->get_id();
            $is_new_product = true;

            // Set vendor
            wp_update_post([
                'ID' => $product_id,
                'post_author' => $vendor_id,
            ]);
        }

        if (!$product_id) {
            return $this->error('no_product', __('Product not defined.', 'wahra-rentals-bookings'));
        }

        $product = wc_get_product($product_id);
        if (!$product) {
            return $this->error('product_not_found', __('Product not found.', 'wahra-rentals-bookings'), 404);
        }

        // Update product meta from wizard data
        $this->apply_wizard_data_to_product($product_id, $wizard_data);

        // TRIGGER DOKAN HOOKS (only in multi-vendor mode)
        // Required for emails, stats, and other Dokan modules to react
        if (wahrb_is_dokan_active()) {
            if ($is_new_product) {
                do_action('dokan_new_product_added', $product_id, [
                    'post_title' => $product->get_name(),
                    'post_content' => $product->get_description(),
                    'post_status' => 'publish',
                ]);
            } else {
                do_action('dokan_product_updated', $product_id, [
                    'post_title' => $product->get_name(),
                    'post_content' => $product->get_description(),
                    'post_status' => 'publish',
                ]);
            }
        }

        // Create price rules
        if (!empty($wizard_data['step_4']['rules'])) {
            $this->create_price_rules($product_id, $vendor_id, $wizard_data['step_4']['rules']);
        }

        // Note: Images (step_6) removed - handled at product level

        // Delete draft after successful publish (instead of keeping as 'published')
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $wpdb->delete(
            $db->table('wizard_drafts'),
            ['draft_id' => $draft_id],
            ['%d']
        );

        // Log
        $db->log('offer_published', 'product', $product_id, [
            'draft_id' => $draft_id,
            'vendor_id' => $vendor_id,
        ]);

        // Build edit URL based on operating mode
        $edit_url = wahrb_is_dokan_active() && function_exists('dokan_get_navigation_url')
            ? dokan_get_navigation_url('products') . 'edit/' . $product_id
            : admin_url('post.php?post=' . $product_id . '&action=edit');

        return $this->success([
            'product_id' => $product_id,
            'product_url' => get_permalink($product_id),
            'edit_url' => $edit_url,
            'message' => __('Listing published successfully!', 'wahra-rentals-bookings'),
        ]);
    }

    /**
     * Apply wizard data to product
     *
     * @param int $product_id Product ID
     * @param array $wizard_data Wizard data
     */
    private function apply_wizard_data_to_product(int $product_id, array $wizard_data): void {
        $step1 = $wizard_data['step_1'] ?? [];
        $step2 = $wizard_data['step_2'] ?? [];
        $step3 = $wizard_data['step_3'] ?? [];
        $step4 = $wizard_data['step_4'] ?? [];
        $step5 = $wizard_data['step_5'] ?? [];
        $step6 = $wizard_data['step_6'] ?? [];

        // Enable rental
        update_post_meta($product_id, '_wahrb_rental_enabled', 'yes');

        // Platform category (primary) and booking mode (derived)
        $platform_category = $step1['platform_category'] ?? '';
        $offer_type = $step1['offer_type'] ?? 'day';

        // Auto-resolve offer_type from platform_category if available
        if (!empty($platform_category) && class_exists('WAHRB_Platform_Categories')) {
            $modes = WAHRB_Platform_Categories::get_booking_modes($platform_category);
            if (!empty($modes) && !in_array($offer_type, $modes, true)) {
                $offer_type = $modes[0];
            }
        }

        // Validate offer_type
        if (!in_array($offer_type, ['day', 'slot', 'service'])) {
            $offer_type = 'day';
        }
        update_post_meta($product_id, '_wahrb_booking_mode', $offer_type);

        // Derive platform category from offer type if not set (backward compat)
        if (empty($platform_category) && class_exists('WAHRB_Platform_Categories')) {
            $platform_category = WAHRB_Platform_Categories::mode_to_category($offer_type);
        }
        if (!empty($platform_category)) {
            update_post_meta($product_id, '_wahrb_platform_category', sanitize_key($platform_category));
        }

        // Inventory
        if (!empty($step2['total_units'])) {
            $total_units = absint($step2['total_units']);
            update_post_meta($product_id, '_wahrb_total_units', $total_units);
            
            // Enable WooCommerce stock management
            update_post_meta($product_id, '_manage_stock', 'yes');
            update_post_meta($product_id, '_stock', $total_units);
            update_post_meta($product_id, '_stock_status', $total_units > 0 ? 'instock' : 'outofstock');
        }

        // Rental description (specific to rental, separate from product description)
        if (!empty($step2['rental_description'])) {
            update_post_meta($product_id, '_wahrb_rental_description', wp_kses_post($step2['rental_description']));
        }

        // Availability (step 3)
        if (!empty($step3)) {
            update_post_meta($product_id, '_wahrb_recurring_days', $step3['recurring_days'] ?? []);
            update_post_meta($product_id, '_wahrb_recurring_hours', $step3['recurring_hours'] ?? []);
            
            $min_duration = absint($step3['min_duration'] ?? 1);
            $max_duration = absint($step3['max_duration'] ?? 30);
            
            // Enforce logic
            if ($min_duration > $max_duration) $min_duration = $max_duration;
            
            update_post_meta($product_id, '_wahrb_min_duration', $min_duration);
            update_post_meta($product_id, '_wahrb_max_duration', $max_duration);
            update_post_meta($product_id, '_wahrb_min_booking_window', absint($step3['min_booking_window'] ?? 24));
            update_post_meta($product_id, '_wahrb_max_booking_window', absint($step3['max_booking_window'] ?? 365));
            update_post_meta($product_id, '_wahrb_buffer_before', absint($step3['buffer_before'] ?? 0));
            update_post_meta($product_id, '_wahrb_buffer_after', absint($step3['buffer_after'] ?? 0));
        }

        // Pricing (step 4)
        if (!empty($step4)) {
            $base_price = max(0, floatval($step4['base_price'] ?? 0));
            update_post_meta($product_id, '_price', $base_price);
            update_post_meta($product_id, '_regular_price', $base_price);
            update_post_meta($product_id, '_wahrb_base_price', $base_price);
            
            $price_unit = $step4['price_unit'] ?? 'day';
            if (!in_array($price_unit, ['day', 'hour', 'slot'])) {
                $price_unit = 'day';
            }
            update_post_meta($product_id, '_wahrb_price_unit', $price_unit);

            // Quick rules (weekend, long_stay, early_bird, last_minute)
            if (!empty($step4['quick_rules']) && is_array($step4['quick_rules'])) {
                $sanitized_quick_rules = [];
                foreach ($step4['quick_rules'] as $rule_key => $rule_data) {
                    if (!is_array($rule_data)) continue;
                    $sanitized_quick_rules[sanitize_key($rule_key)] = [
                        'enabled' => !empty($rule_data['enabled']),
                        'icon' => sanitize_text_field($rule_data['icon'] ?? '📅'),
                        'value' => intval($rule_data['value'] ?? 0),
                        'days' => isset($rule_data['days']) && is_array($rule_data['days']) 
                            ? array_map('sanitize_key', $rule_data['days']) 
                            : [],
                        'threshold' => absint($rule_data['threshold'] ?? 0),
                        'show_client' => !empty($rule_data['show_client']),
                    ];
                }
                update_post_meta($product_id, '_wahrb_quick_rules', $sanitized_quick_rules);
            }

            // Custom rules
            if (!empty($step4['custom_rules']) && is_array($step4['custom_rules'])) {
                $sanitized_custom_rules = [];
                foreach ($step4['custom_rules'] as $rule_data) {
                    if (!is_array($rule_data) || empty($rule_data['name'])) continue;
                    $sanitized_custom_rules[] = [
                        'name' => sanitize_text_field($rule_data['name']),
                        'icon' => sanitize_text_field($rule_data['icon'] ?? '🏷️'),
                        'value' => intval($rule_data['value'] ?? 0),
                        'type' => sanitize_key($rule_data['type'] ?? 'always'),
                        'conditions' => sanitize_text_field($rule_data['conditions'] ?? ''),
                        'condition_label' => sanitize_text_field($rule_data['condition_label'] ?? ''),
                        'show_client' => !empty($rule_data['show_client']),
                    ];
                }
                update_post_meta($product_id, '_wahrb_custom_rules', $sanitized_custom_rules);
            }
        }

        // Payment settings (step 5)
        if (!empty($step5)) {
            // Deposit
            update_post_meta($product_id, '_wahrb_deposit_enabled', !empty($step5['deposit_enabled']) ? 'yes' : 'no');
            update_post_meta($product_id, '_wahrb_deposit_type', sanitize_text_field($step5['deposit_type'] ?? 'percent'));
            update_post_meta($product_id, '_wahrb_deposit_value', floatval($step5['deposit_value'] ?? 30));
            update_post_meta($product_id, '_wahrb_deposit_refundable', !empty($step5['deposit_refundable']) ? 'yes' : 'no');

            // Security deposit
            update_post_meta($product_id, '_wahrb_security_deposit_enabled', !empty($step5['security_enabled']) ? 'yes' : 'no');
            update_post_meta($product_id, '_wahrb_security_deposit', floatval($step5['security_amount'] ?? 0));
            update_post_meta($product_id, '_wahrb_security_mode', sanitize_text_field($step5['security_mode'] ?? 'capture'));

            // Balance
            update_post_meta($product_id, '_wahrb_balance_enabled', !empty($step5['balance_enabled']) ? 'yes' : 'no');
            update_post_meta($product_id, '_wahrb_balance_due_days', absint($step5['balance_due_days'] ?? 3));
            update_post_meta($product_id, '_wahrb_balance_allow_cod', !empty($step5['balance_allow_cod']) ? 'yes' : 'no');
        }

        // Cancellation policy (step 6 - publication)
        if (!empty($step6)) {
            $policy_type = sanitize_text_field($step6['cancellation_policy'] ?? 'flexible');
            update_post_meta($product_id, '_wahrb_cancellation_policy', $policy_type);
            
            // Handle custom vs standard policies
            if ($policy_type === 'custom') {
                update_post_meta($product_id, '_wahrb_cancel_policy_days', absint($step6['cancellation_days'] ?? 0));
                update_post_meta($product_id, '_wahrb_cancel_policy_refund', floatval($step6['cancellation_refund'] ?? 0));
            } elseif (in_array($policy_type, ['flexible', 'moderate', 'strict'])) {
                // Defaults for standard policies
                $defaults = [
                    'flexible' => ['days' => 1, 'refund' => 100],
                    'moderate' => ['days' => 5, 'refund' => 50],
                    'strict' => ['days' => 0, 'refund' => 0],
                ];
                update_post_meta($product_id, '_wahrb_cancel_policy_days', $defaults[$policy_type]['days']);
                update_post_meta($product_id, '_wahrb_cancel_policy_refund', $defaults[$policy_type]['refund']);
            }

            // Terms & Conditions
            if (!empty($step6['terms_accepted'])) {
                update_post_meta($product_id, '_wahrb_terms_accepted', 'yes');
            }
            if (!empty($step6['terms_content'])) {
                update_post_meta($product_id, '_wahrb_terms_content', wp_kses_post($step6['terms_content']));
            }
            if (!empty($step6['terms_file_url'])) {
                update_post_meta($product_id, '_wahrb_terms_file_url', esc_url_raw($step6['terms_file_url']));
            }
        }
    }

    /**
     * Create price rules
     *
     * @param int $product_id Product ID
     * @param int $vendor_id Vendor ID
     * @param array $rules Rules data
     */
    private function create_price_rules(int $product_id, int $vendor_id, array $rules): void {
        global $wpdb;
        $db = WAHRB_Database::instance();

        // Delete existing rules for product
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $wpdb->delete(
            $db->table('price_rules'),
            ['product_id' => $product_id]
        );

        foreach ($rules as $priority => $rule) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
            $wpdb->insert(
                $db->table('price_rules'),
                [
                    'vendor_id' => $vendor_id,
                    'product_id' => $product_id,
                    'rule_name' => sanitize_text_field($rule['name'] ?? ''),
                    'rule_type' => sanitize_text_field($rule['type']),
                    'conditions' => wp_json_encode($rule['conditions'] ?? []),
                    'modifier_type' => sanitize_text_field($rule['modifier_type']),
                    'modifier_value' => floatval($rule['modifier_value']),
                    'priority' => $priority + 1,
                    'is_active' => 1,
                    'created_at' => current_time('mysql'),
                ]
            );
        }
    }

    /**
     * Set product images
     *
     * @param int $product_id Product ID
     * @param array $images Image attachment IDs
     */
    private function set_product_images(int $product_id, array $images): void {
        if (empty($images)) {
            return;
        }

        $product = wc_get_product($product_id);
        if (!$product) {
            return;
        }

        // Process images array to extract IDs
        $image_ids = [];
        foreach ($images as $img) {
            if (is_array($img) && isset($img['id'])) {
                $image_ids[] = absint($img['id']);
            } elseif (is_numeric($img)) {
                $image_ids[] = absint($img);
            }
        }

        if (empty($image_ids)) {
            return;
        }

        // First image is featured
        $product->set_image_id($image_ids[0]);

        // Rest are gallery
        if (count($image_ids) > 1) {
            $gallery = array_slice($image_ids, 1);
            $product->set_gallery_image_ids($gallery);
        }

        $product->save();
    }

    /**
     * Get vendor products
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response|WP_Error
     */
    public function get_products($request) {
        $vendor_id = $this->get_vendor_id();
        $search = sanitize_text_field($request->get_param('search'));
        $rental_only = (bool) $request->get_param('rental_only');

        $args = [
            'post_type' => 'product',
            'post_status' => ['publish', 'draft'],
            'author' => $vendor_id,
            'posts_per_page' => 50,
            'orderby' => 'title',
            'order' => 'ASC',
        ];

        if ($search) {
            $args['s'] = $search;
        }

        if ($rental_only) {
            $args['meta_query'] = [
                [
                    'key' => '_wahrb_rental_enabled',
                    'value' => 'yes',
                ],
            ];
        }

        $query = new WP_Query($args);
        $products = [];

        foreach ($query->posts as $post) {
            $product = wc_get_product($post->ID);
            if (!$product) {
                continue;
            }

            $products[] = [
                'id' => $product->get_id(),
                'name' => $product->get_name(),
                'price' => $product->get_price(),
                'image' => wp_get_attachment_url($product->get_image_id()),
                'rental_enabled' => get_post_meta($post->ID, '_wahrb_rental_enabled', true) === 'yes',
                'status' => $post->post_status,
            ];
        }

        return $this->success($products);
    }

    /**
     * Price preview
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response|WP_Error
     */
    public function price_preview($request) {
        $base_price = floatval($request->get_param('base_price'));
        $rules = $request->get_param('rules');
        $start_date = $this->sanitize_date($request->get_param('start_date'));
        $end_date = $this->sanitize_date($request->get_param('end_date'));
        $qty = absint($request->get_param('qty')) ?: 1;

        if (!$start_date || !$end_date) {
            return $this->error('invalid_dates', __('Dates invalides.', 'wahra-rentals-bookings'));
        }

        // Calculate using pricing engine
        $engine = WAHRB_Pricing_Engine::instance();

        // Create temporary rules for calculation
        $temp_rules = [];
        foreach ($rules as $priority => $rule) {
            $temp_rules[] = new WAHRB_Price_Rule([
                'rule_type' => $rule['type'],
                'conditions' => $rule['conditions'] ?? [],
                'modifier_type' => $rule['modifier_type'],
                'modifier_value' => floatval($rule['modifier_value']),
                'priority' => $priority + 1,
                'is_active' => 1,
            ]);
        }

        $calculation = $engine->calculate_with_rules($base_price, $start_date, $end_date, $qty, $temp_rules);

        return $this->success([
            'breakdown' => $calculation['breakdown'],
            'subtotal' => $calculation['subtotal'],
            'total' => $calculation['total'],
            'days' => $calculation['days'],
        ]);
    }

    /**
     * Upload image
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response|WP_Error
     */
    public function upload_image($request) {
        $files = $request->get_file_params();

        if (empty($files['file'])) {
            return $this->error('no_file', __('No file uploaded.', 'wahra-rentals-bookings'));
        }

        require_once ABSPATH . 'wp-admin/includes/image.php';
        require_once ABSPATH . 'wp-admin/includes/file.php';
        require_once ABSPATH . 'wp-admin/includes/media.php';

        $attachment_id = media_handle_upload('file', 0);

        if (is_wp_error($attachment_id)) {
            return $attachment_id;
        }

        return $this->success([
            'id' => $attachment_id,
            'url' => wp_get_attachment_url($attachment_id),
            'thumbnail' => wp_get_attachment_image_url($attachment_id, 'thumbnail'),
        ], 201);
    }

    /**
     * Get settings (default values for wizard)
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response|WP_Error
     */
    public function get_settings($request) {
        // Get all admin settings
        $general_settings = get_option('wahrb_settings_general', []);
        $booking_settings = get_option('wahrb_settings_booking', []);
        $payment_settings = get_option('wahrb_settings_payment', []);
        $notification_settings = get_option('wahrb_settings_notifications', []);

        return $this->success([
            // General settings
            'general' => [
                'timezone' => $general_settings['timezone'] ?? wp_timezone_string(),
                'wizard_welcome_text' => $general_settings['wizard_welcome_text'] ?? '',
                'date_format' => $general_settings['date_format'] ?? 'Y-m-d',
                'time_format' => $general_settings['time_format'] ?? '24h',
                // Terms & Conditions
                'terms_url' => $general_settings['terms_url'] ?? '',
                'vendor_consent_text' => $general_settings['vendor_consent_text'] ?? __('I accept the terms and conditions', 'wahra-rentals-bookings'),
                'terms_required' => $general_settings['terms_required'] ?? true,
            ],
            // Booking settings
            'booking' => [
                'min_booking_window_hours' => $booking_settings['min_booking_window_hours'] ?? 24,
                'max_booking_window_days' => $booking_settings['max_booking_window_days'] ?? 365,
                'buffer_before_hours' => $booking_settings['buffer_before_hours'] ?? 0,
                'buffer_after_hours' => $booking_settings['buffer_after_hours'] ?? 0,
                'default_min_stay_days' => $booking_settings['default_min_stay_days'] ?? 1,
                'default_max_stay_days' => $booking_settings['default_max_stay_days'] ?? 30,
                'hold_duration_minutes' => $booking_settings['hold_duration_minutes'] ?? 30,
            ],
            // Payment settings - per category
            'payment' => WAHRB_Platform_Categories::get_all_payment_settings(),
            // Service types derived from platform categories
            'service_types' => $this->filter_enabled_service_types(),
            // Platform categories (full config for React wizard)
            'platform_categories' => WAHRB_Platform_Categories::get_js_config(),
            // Notifications settings
            'notifications' => [
                'balance_reminder_days' => $notification_settings['balance_reminder_days'] ?? 3,
            ],
            // Per-category pricing rules
            'pricing_rules' => $this->get_platform_pricing_rules(),
            // Vendor permissions
            'vendor_permissions' => WAHRB_Vendor_Permissions::get_js_config(),
            // Currency info (override WooCommerce if set in admin)
            'currency' => get_woocommerce_currency(),
            'currency_symbol' => !empty($general_settings['currency_symbol']) ? $general_settings['currency_symbol'] : html_entity_decode(get_woocommerce_currency_symbol(), ENT_QUOTES, 'UTF-8'),
            'currency_position' => $general_settings['currency_position'] ?? 'before',
        ]);
    }

    /**
     * Filter service types to only include enabled ones
     *
     * @param array $service_types All service types
     * @return array Enabled service types only
     */
    private function filter_enabled_service_types(): array {
        $enabled = WAHRB_Platform_Categories::get_enabled();
        $modes = [];
        $mode_labels = [
            'day' => [
                'title' => __('Daily rental', 'wahra-rentals-bookings'),
                'description' => __('Reservation by full day', 'wahra-rentals-bookings'),
            ],
            'slot' => [
                'title' => __('Time slot booking', 'wahra-rentals-bookings'),
                'description' => __('Reservation on specific time slots', 'wahra-rentals-bookings'),
            ],
            'service' => [
                'title' => __('One-time service', 'wahra-rentals-bookings'),
                'description' => __('Single service on a specific date', 'wahra-rentals-bookings'),
            ],
        ];

        foreach ($enabled as $cat) {
            foreach ($cat['booking_modes'] as $mode) {
                if (!isset($modes[$mode]) && isset($mode_labels[$mode])) {
                    $modes[$mode] = $mode_labels[$mode];
                }
            }
        }

        return $modes;
    }

    /**
     * Get per-category pricing rules for the wizard.
     *
     * @return array Pricing rules keyed by category slug
     */
    private function get_platform_pricing_rules(): array {
        $enabled = WAHRB_Platform_Categories::get_enabled();
        $result = [];

        foreach ($enabled as $slug => $cat) {
            $result[$slug] = WAHRB_Platform_Categories::get_category_pricing($slug);
        }

        return $result;
    }

    /**
     * Recursively sanitize array data
     *
     * @param mixed $data Data to sanitize
     * @return mixed Sanitized data
     */
    private function sanitize_recursive($data) {
        if (is_array($data)) {
            foreach ($data as $key => $value) {
                $data[$key] = $this->sanitize_recursive($value);
            }
        } elseif (is_string($data)) {
            return sanitize_text_field($data);
        }
        return $data;
    }
}
