<?php
/**
 * Bulk Operations REST API Controller
 *
 * @package VariationHub
 */

namespace VariationHub\API;

use VariationHub\Core\License_Manager;

defined('ABSPATH') || exit;

/**
 * Bulk Operations Controller Class
 */
class Bulk_Operations_Controller extends \WP_REST_Controller {
    
    /**
     * Namespace
     *
     * @var string
     */
    protected $namespace = 'variation-hub/v1';
    
    /**
     * Rest base
     *
     * @var string
     */
    protected $rest_base = 'bulk';
    
    /**
     * Register routes
     */
    public function register_routes() {
        // POST /bulk/preview - Preview changes (dry-run)
        register_rest_route($this->namespace, '/' . $this->rest_base . '/preview', [
            [
                'methods'             => \WP_REST_Server::CREATABLE,
                'callback'            => [$this, 'preview_bulk_update'],
                'permission_callback' => [$this, 'update_items_permissions_check'],
                'args'                => $this->get_bulk_update_args(),
            ],
        ]);
        
        // POST /bulk/update - Apply bulk updates
        register_rest_route($this->namespace, '/' . $this->rest_base . '/update', [
            [
                'methods'             => \WP_REST_Server::CREATABLE,
                'callback'            => [$this, 'bulk_update'],
                'permission_callback' => [$this, 'update_items_permissions_check'],
                'args'                => $this->get_bulk_update_args(),
            ],
        ]);
    }
    
    /**
     * Preview bulk update (dry-run)
     *
     * @param \WP_REST_Request $request Full request object.
     * @return \WP_REST_Response|\WP_Error
     */
    public function preview_bulk_update($request) {
        $params = $request->get_json_params();

        $variation_ids = isset($params['variation_ids']) ? array_map('absint', $params['variation_ids']) : [];
        $operations = isset($params['operations']) ? $params['operations'] : [];

        if (empty($variation_ids)) {
            return new \WP_Error(
                'variation_hub_no_variations',
                __('No variations selected', 'variation-hub'),
                ['status' => 400]
            );
        }

        if (empty($operations)) {
            return new \WP_Error(
                'variation_hub_no_operations',
                __('No operation specified', 'variation-hub'),
                ['status' => 400]
            );
        }

        // 🔒 SECURITY: Check if SKU operations require PRO license
        foreach ($operations as $operation) {
            if (isset($operation['field']) && $operation['field'] === 'sku') {
                if (!License_Manager::has_feature('sku_generator')) {
                    return new \WP_Error(
                        'variation_hub_sku_generator_pro_only',
                        __('SKU Generator is available in PRO version only. Please upgrade to access this feature.', 'variation-hub'),
                        ['status' => 403]
                    );
                }
                break; // Only need to check once
            }
        }

        // ✅ LICENSE CHECK: Bulk operations limit (FREE: 10 variations max)
        $bulk_limit = License_Manager::get_limit('bulk_operations_limit');
        if ($bulk_limit > 0 && count($variation_ids) > $bulk_limit) {
            return new \WP_Error(
                'variation_hub_bulk_limit_exceeded',
                sprintf(
                    /* translators: 1: limit, 2: selected count */
                    __('Ingyenes verzióban max %1$d variáció módosítható egyszerre. Kijelöltél: %2$d. Frissíts Pro verzióra korlátlan tömeges műveletekért!', 'variation-hub'),
                    $bulk_limit,
                    count($variation_ids)
                ),
                ['status' => 403]
            );
        }
        
        $preview = [];
        
        foreach ($variation_ids as $variation_id) {
            $variation = wc_get_product($variation_id);
            
            if (!$variation || $variation->get_type() !== 'variation') {
                continue;
            }
            
            // ✅ SECURITY FIX 8: Check permission for preview as well
            $parent_id = $variation->get_parent_id();
            if (!current_user_can('edit_product', $parent_id) && !current_user_can('edit_post', $parent_id)) {
                continue; // Skip variations user doesn't have permission to edit
            }
            
            $changes = [
                'id' => $variation_id,
                'sku' => $variation->get_sku(),
            ];
            
            // Calculate new values for each operation
            foreach ($operations as $operation) {
                $field = $operation['field'];
                $op_type = $operation['operation'];
                $value = $operation['value'];
                $rounding = !empty($operation['rounding']) ? (int) $operation['rounding'] : 0;
                
                if ($field === 'price' || $field === 'regular_price') {
                    $current_price = (float) $variation->get_regular_price();
                    $changes['current_price'] = $current_price;
                    $changes['new_price'] = $this->calculate_price($current_price, $op_type, $value, $rounding);
                } elseif ($field === 'sale_price') {
                    $current_sale = (float) $variation->get_sale_price();
                    $changes['current_sale_price'] = $current_sale;
                    $changes['new_sale_price'] = $this->calculate_price($current_sale, $op_type, $value, $rounding);
                    
                    // Sale dates (if provided)
                    if (!empty($operation['date_from'])) {
                        $changes['sale_date_from'] = $operation['date_from'];
                    }
                    if (!empty($operation['date_to'])) {
                        $changes['sale_date_to'] = $operation['date_to'];
                    }
                } elseif ($field === 'stock_quantity') {
                    $current_stock = $variation->get_stock_quantity();
                    $changes['current_stock'] = $current_stock;
                    $changes['new_stock'] = $this->calculate_stock($current_stock, $op_type, $value);
                } elseif ($field === 'sku') {
                    $changes['current_sku'] = $variation->get_sku();
                    $changes['new_sku'] = $this->generate_sku($variation, $value);
                } elseif ($field === 'image') {
                    // Image assignment
                    $current_image_id = $variation->get_image_id();
                    $new_image_id = absint($value);
                    
                    $changes['current_image_id'] = $current_image_id;
                    $changes['current_image_url'] = $current_image_id ? wp_get_attachment_image_url($current_image_id, 'thumbnail') : '';
                    $changes['new_image_id'] = $new_image_id;
                    $changes['new_image_url'] = $new_image_id ? wp_get_attachment_image_url($new_image_id, 'thumbnail') : '';
                }
            }
            
            $preview[] = $changes;
        }
        
        return rest_ensure_response([
            'success' => true,
            'data' => [
                'preview' => $preview,
                'count' => count($preview),
            ],
        ]);
    }
    
    /**
     * Apply bulk update
     *
     * @param \WP_REST_Request $request Full request object.
     * @return \WP_REST_Response|\WP_Error
     */
    public function bulk_update($request) {
        $params = $request->get_json_params();

        $variation_ids = isset($params['variation_ids']) ? array_map('absint', $params['variation_ids']) : [];
        $operations = isset($params['operations']) ? $params['operations'] : [];

        if (empty($variation_ids)) {
            return new \WP_Error(
                'variation_hub_no_variations',
                __('No variations selected', 'variation-hub'),
                ['status' => 400]
            );
        }

        // 🔒 SECURITY: Check if SKU operations require PRO license
        foreach ($operations as $operation) {
            if (isset($operation['field']) && $operation['field'] === 'sku') {
                if (!License_Manager::has_feature('sku_generator')) {
                    return new \WP_Error(
                        'variation_hub_sku_generator_pro_only',
                        __('SKU Generator is available in PRO version only. Please upgrade to access this feature.', 'variation-hub'),
                        ['status' => 403]
                    );
                }
                break; // Only need to check once
            }
        }

        // ✅ LICENSE CHECK: Bulk operations limit (FREE: 10 variations max)
        $bulk_limit = License_Manager::get_limit('bulk_operations_limit');
        if ($bulk_limit > 0 && count($variation_ids) > $bulk_limit) {
            return new \WP_Error(
                'variation_hub_bulk_limit_exceeded',
                sprintf(
                    /* translators: 1: limit, 2: selected count */
                    __('Ingyenes verzióban max %1$d variáció módosítható egyszerre. Kijelöltél: %2$d. Frissíts Pro verzióra korlátlan tömeges műveletekért!', 'variation-hub'),
                    $bulk_limit,
                    count($variation_ids)
                ),
                ['status' => 403]
            );
        }
        
        $processed = 0;
        $failed = 0;
        $errors = [];
        $processed_ids = []; // ✅ Track successfully processed IDs for bulk cache sync
        
        // ✅ PERFORMANCE FIX: Temporarily unhook cache sync to avoid race condition
        remove_action('woocommerce_update_product_variation', ['\VariationHub\Core\Cache_Hooks', 'on_variation_saved']);
        
        foreach ($variation_ids as $variation_id) {
            $variation = wc_get_product($variation_id);
            
            if (!$variation || $variation->get_type() !== 'variation') {
                $failed++;
                /* translators: %d: variation ID */
                $errors[] = sprintf(__('Invalid variation: %d', 'variation-hub'), $variation_id);
                continue;
            }
            
            // ✅ SECURITY FIX: Check if user can edit the parent product
            $parent_id = $variation->get_parent_id();
            if (!current_user_can('edit_product', $parent_id) && !current_user_can('edit_post', $parent_id)) {
                $failed++;
                /* translators: %d: variation ID */
                $errors[] = sprintf(__('You do not have permission for this variation: %d', 'variation-hub'), $variation_id);
                continue;
            }
            
            try {
                foreach ($operations as $operation) {
                    $field = $operation['field'];
                    $op_type = $operation['operation'];
                    $value = $operation['value'];
                    $rounding = !empty($operation['rounding']) ? (int) $operation['rounding'] : 0;
                    
                    if ($field === 'price' || $field === 'regular_price') {
                        $current_price = (float) $variation->get_regular_price();
                        $new_price = $this->calculate_price($current_price, $op_type, $value, $rounding);
                        $variation->set_regular_price($new_price);
                    } elseif ($field === 'sale_price') {
                        $current_sale = (float) $variation->get_sale_price();
                        $new_sale = $this->calculate_price($current_sale, $op_type, $value, $rounding);
                        
                        // Set sale price
                        if ($op_type === 'remove' || empty($new_sale)) {
                            // Remove sale price
                            $variation->set_sale_price('');
                            $variation->set_date_on_sale_from('');
                            $variation->set_date_on_sale_to('');
                        } else {
                            $variation->set_sale_price($new_sale);
                            
                            // Set sale dates (if provided)
                            if (!empty($operation['date_from'])) {
                                $date_from = strtotime($operation['date_from']);
                                $variation->set_date_on_sale_from($date_from ? $date_from : '');
                            }
                            if (!empty($operation['date_to'])) {
                                $date_to = strtotime($operation['date_to']);
                                $variation->set_date_on_sale_to($date_to ? $date_to : '');
                            }
                        }
                    } elseif ($field === 'stock_quantity') {
                        $current_stock = $variation->get_stock_quantity();
                        $new_stock = $this->calculate_stock($current_stock, $op_type, $value);
                        $variation->set_stock_quantity($new_stock);
                    } elseif ($field === 'sku') {
                        $new_sku = $this->generate_sku($variation, $value);
                        $variation->set_sku($new_sku);
                    } elseif ($field === 'image') {
                        $new_image_id = absint($value);
                        // Ha 0, akkor töröljük a képet
                        if ($new_image_id === 0) {
                            $variation->set_image_id(0);
                        } else {
                            $variation->set_image_id($new_image_id);
                        }
                    }
                }
                
                $variation->save();
                $processed++;
                $processed_ids[] = $variation_id; // ✅ Track successful save
                
            } catch (\Exception $e) {
                $failed++;
                $errors[] = sprintf(
                    /* translators: 1: variation ID, 2: error message */
                    __('Error updating variation %1$d: %2$s', 'variation-hub'),
                    $variation_id,
                    $e->getMessage()
                );
            }
        }
        
        // ✅ PERFORMANCE FIX: Re-hook cache sync
        add_action('woocommerce_update_product_variation', ['\VariationHub\Core\Cache_Hooks', 'on_variation_saved']);
        
        // ✅ PERFORMANCE FIX: Bulk cache sync all processed variations at once (no race condition!)
        if (!empty($processed_ids)) {
            \VariationHub\Core\Cache_Sync::bulk_sync_variations($processed_ids);
        }
        
        return rest_ensure_response([
            'success' => $failed === 0,
            'message' => sprintf(
                /* translators: %d: number of variations updated */
                __('%d variations updated successfully', 'variation-hub'),
                $processed
            ),
            'data' => [
                'processed' => $processed,
                'failed' => $failed,
                'errors' => $errors,
            ],
        ]);
    }
    
    /**
     * Calculate new price
     *
     * @param float $current Current price.
     * @param string $operation Operation type.
     * @param string $value Value.
     * @param int $rounding Optional rounding value.
     * @return float
     * @throws \Exception If value is out of valid range.
     */
    protected function calculate_price($current, $operation, $value, $rounding = 0) {
        $value = (float) $value;
        
        $new_price = $current;
        
        switch ($operation) {
            case 'percentage':
                // ✅ SERVER-SIDE VALIDATION: Percentage range
                if ($value < -100 || $value > 1000) {
                    throw new \Exception(
                        esc_html__('Percentage must be between -100% and +1000%', 'variation-hub')
                    );
                }
                // Percentage change (e.g., -20 means -20%)
                $new_price = $current * (1 + ($value / 100));
                break;
                
            case 'fixed':
                // ✅ SERVER-SIDE VALIDATION: Fixed amount range
                if ($value < -10000000 || $value > 10000000) {
                    throw new \Exception(
                        esc_html__('Price value must be between -10,000,000 and +10,000,000', 'variation-hub')
                    );
                }
                // Fixed amount change (e.g., +500 or -500)
                $new_price = $current + $value;
                break;
                
            case 'set':
                // ✅ SERVER-SIDE VALIDATION: Set value range
                if ($value < 0 || $value > 10000000) {
                    throw new \Exception(
                        esc_html__('Price must be between 0 and 10,000,000', 'variation-hub')
                    );
                }
                // Set to specific value
                $new_price = $value;
                break;
                
            case 'remove':
                // Remove (for sale price)
                return 0;
                
            default:
                $new_price = $current;
        }
        
        // Apply rounding if specified
        if ($rounding > 0) {
            $new_price = round($new_price / $rounding) * $rounding;
        } else {
            // Default: round to whole number (no decimals)
            $new_price = round($new_price);
        }
        
        return max(0, $new_price);
    }
    
    /**
     * Calculate new stock
     *
     * @param int $current Current stock.
     * @param string $operation Operation type.
     * @param string $value Value.
     * @return int
     * @throws \Exception If value is out of valid range.
     */
    protected function calculate_stock($current, $operation, $value) {
        $value = (int) $value;
        
        // ✅ SERVER-SIDE VALIDATION: Stock value range
        if ($value < -10000 || $value > 100000) {
            throw new \Exception(
                esc_html__('Stock value must be between -10,000 and +100,000', 'variation-hub')
            );
        }
        
        switch ($operation) {
            case 'increment':
                return $current + $value;
                
            case 'decrement':
                return max(0, $current - $value);
                
            case 'set':
                return max(0, $value); // Ensure non-negative stock
                
            default:
                return $current;
        }
    }
    
    /**
     * Generate SKU from pattern
     *
     * @param \WC_Product_Variation $variation Variation object.
     * @param string $pattern SKU pattern.
     * @return string
     */
    protected function generate_sku($variation, $pattern) {
        $parent = wc_get_product($variation->get_parent_id());
        $attributes = $variation->get_attributes();
        
        // Replace placeholders
        $sku = $pattern;
        $sku = str_replace('{parent_sku}', $parent ? $parent->get_sku() : '', $sku);
        $sku = str_replace('{id}', $variation->get_id(), $sku);
        
        // Replace attribute placeholders
        foreach ($attributes as $key => $value) {
            $sku = str_replace('{' . $key . '}', strtoupper($value), $sku);
        }
        
        return $sku;
    }
    
    /**
     * Check permissions
     *
     * @param \WP_REST_Request $request Full request object.
     * @return bool|\WP_Error
     */
    public function update_items_permissions_check($request) {
        if (!current_user_can('manage_woocommerce')) {
            return new \WP_Error(
                'variation_hub_forbidden',
                __('You do not have permission for bulk operations', 'variation-hub'),
                ['status' => 403]
            );
        }
        
        return true;
    }
    
    /**
     * Get bulk update arguments
     *
     * @return array
     */
    protected function get_bulk_update_args() {
        return [
            'variation_ids' => [
                'description' => __('Array of variation IDs', 'variation-hub'),
                'type'        => 'array',
                'required'    => true,
                'items'       => [
                    'type' => 'integer',
                ],
            ],
            'operations' => [
                'description' => __('Array of operations', 'variation-hub'),
                'type'        => 'array',
                'required'    => true,
                'items'       => [
                    'type' => 'object',
                    'properties' => [
                        'field' => [
                            'type' => 'string',
                            'enum' => ['price', 'regular_price', 'sale_price', 'stock_quantity', 'sku', 'image'],
                        ],
                        'operation' => [
                            'type' => 'string',
                            'enum' => ['percentage', 'fixed', 'set', 'increment', 'decrement', 'pattern'],
                        ],
                        'value' => [
                            'type' => 'string',
                        ],
                    ],
                ],
            ],
        ];
    }
}
