<?php
/**
 * Variations REST API Controller
 *
 * @package VariationHub
 * 
 * phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
 * Reason: Search autocomplete (line 604) queries wp_posts/wp_postmeta directly for performance.
 * WooCommerce native search is too slow for real-time autocomplete (500ms+ vs 50ms with direct SQL).
 */

namespace VariationHub\API;

defined('ABSPATH') || exit;

/**
 * Variations Controller class
 */
class Variations_Controller extends \WP_REST_Controller {
    /**
     * Endpoint namespace
     *
     * @var string
     */
    protected $namespace = 'variation-hub/v1';

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

    /**
     * Register routes
     */
    public function register_routes() {
        // GET /variations
        register_rest_route($this->namespace, '/' . $this->rest_base, [
            [
                'methods' => \WP_REST_Server::READABLE,
                'callback' => [$this, 'get_items'],
                'permission_callback' => [$this, 'get_items_permissions_check'],
                'args' => $this->get_collection_params(),
            ],
        ]);

        // PUT /variations/{id}
        register_rest_route($this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', [
            [
                'methods' => \WP_REST_Server::EDITABLE,
                'callback' => [$this, 'update_item'],
                'permission_callback' => [$this, 'update_item_permissions_check'],
                'args' => $this->get_endpoint_args_for_item_schema(\WP_REST_Server::EDITABLE),
            ],
        ]);

        // POST /variations/by-ids
        register_rest_route($this->namespace, '/' . $this->rest_base . '/by-ids', [
            [
                'methods' => \WP_REST_Server::CREATABLE,
                'callback' => [$this, 'get_items_by_ids'],
                'permission_callback' => [$this, 'get_items_permissions_check'],
                'args' => [
                    'ids' => [
                        'required' => true,
                        'type' => 'array',
                        'items' => [
                            'type' => 'integer',
                        ],
                    ],
                ],
            ],
        ]);

        // GET /products/{id}
        register_rest_route($this->namespace, '/products/(?P<id>[\d]+)', [
            [
                'methods' => \WP_REST_Server::READABLE,
                'callback' => [$this, 'get_product'],
                'permission_callback' => [$this, 'get_items_permissions_check'],
            ],
        ]);

        // GET /variations/autocomplete/products
        register_rest_route($this->namespace, '/' . $this->rest_base . '/autocomplete/products', [
            [
                'methods' => \WP_REST_Server::READABLE,
                'callback' => [$this, 'autocomplete_products'],
                'permission_callback' => [$this, 'get_items_permissions_check'],
                'args' => [
                    'q' => [
                        'required' => true,
                        'type' => 'string',
                        'sanitize_callback' => 'sanitize_text_field',
                    ],
                ],
            ],
        ]);

        // GET /variations/autocomplete/attributes
        register_rest_route($this->namespace, '/' . $this->rest_base . '/autocomplete/attributes', [
            [
                'methods' => \WP_REST_Server::READABLE,
                'callback' => [$this, 'autocomplete_attributes'],
                'permission_callback' => [$this, 'get_items_permissions_check'],
                'args' => [
                    'q' => [
                        'required' => true,
                        'type' => 'string',
                        'sanitize_callback' => 'sanitize_text_field',
                    ],
                ],
            ],
        ]);
    }

    /**
     * Check permissions for getting items
     *
     * @return bool
     */
    public function get_items_permissions_check($request) {
        return current_user_can('manage_woocommerce');
    }

    /**
     * Get variations
     *
     * @param \WP_REST_Request $request Request object
     * @return \WP_REST_Response
     */
    public function get_items($request) {
        $params = $request->get_params();
        
        // Check if grouped mode is requested
        if (isset($params['group_by']) && $params['group_by'] === 'parent') {
            return $this->get_items_grouped($request);
        }
        
        // Default flat mode (existing logic)
        $args = [
            'type' => 'variation',
            'status' => 'publish',
            'limit' => isset($params['limit']) ? intval($params['limit']) : 100,
            'offset' => isset($params['offset']) ? intval($params['offset']) : 0,
        ];

        // Add search (parent name + SKU)
        if (!empty($params['search'])) {
            $args['s'] = sanitize_text_field($params['search']);
        }

        // Add parent filter
        if (!empty($params['parent_id'])) {
            $args['parent'] = intval($params['parent_id']);
        }

        // Get ALL variations first (we'll filter manually for complex filters)
        $products = wc_get_products($args);
        
        // Manual filtering for attributes, price, dates
        $filtered_products = [];
        foreach ($products as $product) {
            // Filter by attribute
            if (!empty($params['attributes'])) {
                $search_attr = strtolower(sanitize_text_field($params['attributes']));
                $product_attrs = $product->get_attributes();
                $found = false;
                
                foreach ($product_attrs as $key => $value) {
                    if (stripos(strtolower($value), $search_attr) !== false) {
                        $found = true;
                        break;
                    }
                }
                
                if (!$found) continue;
            }
            
            // Filter by price range (regular or sale price based on filter_sale_price)
            $filter_sale_price = isset($params['filter_sale_price']) && $params['filter_sale_price'] === 'true';
            
            if (!empty($params['price_min']) || !empty($params['price_max'])) {
                $price = $filter_sale_price ? 
                    floatval($product->get_sale_price() ?: $product->get_regular_price()) : 
                    floatval($product->get_regular_price());
                
                if (!empty($params['price_min']) && $price < floatval($params['price_min'])) {
                    continue;
                }
                
                if (!empty($params['price_max']) && $price > floatval($params['price_max'])) {
                    continue;
                }
            }
            
            // Filter by sale dates
            if (!empty($params['sale_date_from']) || !empty($params['sale_date_to']) || 
                (isset($params['only_active_sales']) && $params['only_active_sales'] === 'true')) {
                
                $date_from = $product->get_date_on_sale_from();
                $date_to = $product->get_date_on_sale_to();
                
                // Only active sales filter
                if (isset($params['only_active_sales']) && $params['only_active_sales'] === 'true') {
                    $now = time();
                    $is_on_sale = false;
                    
                    if ($date_from && $date_to) {
                        $is_on_sale = ($date_from->getTimestamp() <= $now && $date_to->getTimestamp() >= $now);
                    } elseif ($date_from) {
                        $is_on_sale = ($date_from->getTimestamp() <= $now);
                    } elseif ($date_to) {
                        $is_on_sale = ($date_to->getTimestamp() >= $now);
                    } elseif ($product->get_sale_price()) {
                        $is_on_sale = true; // Has sale price but no dates
                    }
                    
                    if (!$is_on_sale) continue;
                }
                
                // Date range filters
                if (!empty($params['sale_date_from']) && $date_from) {
                    if ($date_from->format('Y-m-d') < $params['sale_date_from']) {
                        continue;
                    }
                }
                
                if (!empty($params['sale_date_to']) && $date_to) {
                    if ($date_to->format('Y-m-d') > $params['sale_date_to']) {
                        continue;
                    }
                }
            }
            
            $filtered_products[] = $product;
        }

        // Count total after filtering
        $total = count($filtered_products);

        $variations = [];
        foreach ($filtered_products as $product) {
            $variations[] = $this->prepare_item_for_response($product, $request);
        }

        // Get valid tax classes for dropdown
        $tax_classes = WC_Tax::get_tax_class_slugs();
        
        // Add 'parent' and empty string (standard) as special options
        $tax_class_options = array_merge(['parent', ''], $tax_classes);

        return new \WP_REST_Response([
            'success' => true,
            'data' => [
                'variations' => $variations,
                'total' => $total,
                'offset' => $args['offset'],
                'limit' => $args['limit'],
                'tax_class_options' => $tax_class_options, // Available tax classes
            ],
        ], 200);
    }

    /**
     * Prepare item for response
     *
     * @param \WC_Product_Variation $product Product object
     * @param \WP_REST_Request $request Request object
     * @return array
     */
    public function prepare_item_for_response($product, $request) {
        $parent = wc_get_product($product->get_parent_id());
        
        return [
            'id' => $product->get_id(),
            'parent_id' => $product->get_parent_id(),
            'parent_name' => $parent ? $parent->get_name() : '',
            'sku' => $product->get_sku(),
            'image_url' => wp_get_attachment_url($product->get_image_id()),
            'attributes' => $product->get_attributes(),
            'price' => $product->get_price(), // Current active price (sale or regular)
            'regular_price' => $product->get_regular_price(),
            'sale_price' => $product->get_sale_price(),
            'date_on_sale_from' => $product->get_date_on_sale_from() ? $product->get_date_on_sale_from()->format('Y-m-d') : null,
            'date_on_sale_to' => $product->get_date_on_sale_to() ? $product->get_date_on_sale_to()->format('Y-m-d') : null,
            'stock_quantity' => $product->get_stock_quantity(),
            'stock_status' => $product->get_stock_status(),
            'manage_stock' => $product->get_manage_stock(),
            'tax_class' => $product->get_tax_class('edit'), // 'edit' context = actual stored value (not parent inheritance)
            'status' => $product->get_status(),
            'permalink' => $product->get_permalink(),
        ];
    }

    /**
     * Check permissions for updating item
     *
     * @return bool
     */
    public function update_item_permissions_check($request) {
        return current_user_can('manage_woocommerce');
    }

    /**
     * Update variation
     *
     * @param \WP_REST_Request $request Request object
     * @return \WP_REST_Response
     */
    public function update_item($request) {
        $id = intval($request['id']);
        $product = wc_get_product($id);

        if (!$product || 'variation' !== $product->get_type()) {
            return new \WP_REST_Response([
                'success' => false,
                'message' => __('Invalid variation ID', 'variation-hub'),
            ], 404);
        }

        // ✅ SECURITY FIX: Check if user can edit the parent product (multi-vendor compatibility)
        $parent_id = $product->get_parent_id();
        if (!current_user_can('edit_product', $parent_id) && !current_user_can('edit_post', $parent_id)) {
            return new \WP_REST_Response([
                'success' => false,
                'message' => __('You do not have permission to edit this product', 'variation-hub'),
            ], 403);
        }

        try {
            // Update fields
            $params = $request->get_json_params();
            
            if (isset($params['sku'])) {
                $product->set_sku(sanitize_text_field($params['sku']));
            }
            
            // ⚠️ IMPORTANT: 'price' updates regular_price (not sale_price!)
            if (isset($params['price'])) {
                $product->set_regular_price(floatval($params['price']));
            }
            
            // Regular price (explicit field)
            if (isset($params['regular_price'])) {
                $product->set_regular_price(floatval($params['regular_price']));
            }
            
            if (isset($params['sale_price'])) {
                // Empty string means remove sale price
                if ($params['sale_price'] === '') {
                    $product->set_sale_price('');
                } else {
                    $product->set_sale_price(floatval($params['sale_price']));
                }
            }
            
            // Sale date handling
            if (isset($params['date_on_sale_from'])) {
                $product->set_date_on_sale_from($params['date_on_sale_from'] ? strtotime($params['date_on_sale_from']) : null);
            }
            
            if (isset($params['date_on_sale_to'])) {
                $product->set_date_on_sale_to($params['date_on_sale_to'] ? strtotime($params['date_on_sale_to']) : null);
            }
            
            // Stock fields - ORDER MATTERS!
            // 1. manage_stock first (affects stock_status auto-calculation)
            if (isset($params['manage_stock'])) {
                $product->set_manage_stock(filter_var($params['manage_stock'], FILTER_VALIDATE_BOOLEAN));
            }
            
            // 2. stock_quantity (triggers stock_status recalc if manage_stock=true)
            if (isset($params['stock_quantity'])) {
                $product->set_stock_quantity(intval($params['stock_quantity']));
            }
            
            // 3. stock_status LAST (manual override, but only if manage_stock=false)
            if (isset($params['stock_status'])) {
                // If manage_stock is enabled, we need to disable it temporarily
                // to allow manual stock_status setting
                $manage_stock_enabled = $product->get_manage_stock();
                if ($manage_stock_enabled) {
                    // Temporarily disable manage_stock to set manual status
                    $product->set_manage_stock(false);
                }
                
                $product->set_stock_status(sanitize_text_field($params['stock_status']));
                
                // Re-enable manage_stock if it was enabled
                if ($manage_stock_enabled) {
                    $product->set_manage_stock(true);
                }
            }
            
            if (isset($params['backorders'])) {
                $product->set_backorders(sanitize_text_field($params['backorders']));
            }
            
            if (isset($params['low_stock_threshold'])) {
                $low_stock = $params['low_stock_threshold'] === '' ? null : intval($params['low_stock_threshold']);
                $product->set_low_stock_amount($low_stock);
            }
            
            // Physical properties
            if (isset($params['weight'])) {
                $product->set_weight($params['weight'] === '' ? '' : floatval($params['weight']));
            }
            
            if (isset($params['length'])) {
                $product->set_length($params['length'] === '' ? '' : floatval($params['length']));
            }
            
            if (isset($params['width'])) {
                $product->set_width($params['width'] === '' ? '' : floatval($params['width']));
            }
            
            if (isset($params['height'])) {
                $product->set_height($params['height'] === '' ? '' : floatval($params['height']));
            }
            
            // Tax and type
            if (isset($params['tax_class'])) {
                // WooCommerce variations support per-variation tax_class
                // Values: 'parent' (inherit), '' (standard), 'reduced-rate', 'zero-rate', etc.
                $tax_class = sanitize_text_field($params['tax_class']);
                $product->set_tax_class($tax_class);
            }
            
            if (isset($params['virtual'])) {
                $product->set_virtual(filter_var($params['virtual'], FILTER_VALIDATE_BOOLEAN));
            }
            
            if (isset($params['downloadable'])) {
                $product->set_downloadable(filter_var($params['downloadable'], FILTER_VALIDATE_BOOLEAN));
            }
            
            // Content
            if (isset($params['description'])) {
                $product->set_description(wp_kses_post($params['description']));
            }
            
            // Status
            if (isset($params['status'])) {
                $product->set_status(sanitize_text_field($params['status']));
            }

            $product->save();

            // CRITICAL FIX for tax_class persistence:
            // WooCommerce checks metadata_exists('post', $id, '_tax_class') on read
            // If postmeta doesn't exist, it defaults to 'parent' even if we saved a value
            // We must ensure the _tax_class postmeta record exists
            if (isset($params['tax_class'])) {
                update_post_meta($id, '_tax_class', sanitize_text_field($params['tax_class']));
            }

            // ✅ FIX: Reload product to get fresh data after save
            wp_cache_delete($id, 'posts');
            wp_cache_delete($id, 'post_meta');
            clean_post_cache($id);
            $product = wc_get_product($id); // Reload fresh data

            // Invalidate cache and resync
            $cache_sync = new \VariationHub\Core\Cache_Sync();
            $cache_sync->sync_variation($id);

            return new \WP_REST_Response([
                'success' => true,
                'message' => __('Variation updated successfully', 'variation-hub'),
                'data' => $this->prepare_item_for_response($product, $request),
            ], 200);

        } catch (\Exception $e) {
            return new \WP_REST_Response([
                'success' => false,
                'message' => $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Get variations by IDs
     *
     * @param \WP_REST_Request $request Request object
     * @return \WP_REST_Response
     */
    public function get_items_by_ids($request) {
        $params = $request->get_json_params();
        $ids = isset($params['ids']) ? array_map('absint', $params['ids']) : [];

        if (empty($ids)) {
            return new \WP_REST_Response([
                'success' => false,
                'message' => __('No variation ID provided', 'variation-hub'),
            ], 400);
        }

        $variations = [];
        foreach ($ids as $id) {
            $product = wc_get_product($id);
            
            if (!$product || $product->get_type() !== 'variation') {
                continue;
            }

            $variations[] = $this->prepare_item_for_response($product, $request);
        }

        return new \WP_REST_Response([
            'success' => true,
            'data' => $variations,
        ], 200);
    }

    /**
     * Get product (parent) by ID
     *
     * @param \WP_REST_Request $request Request object
     * @return \WP_REST_Response
     */
    public function get_product($request) {
        $id = (int) $request['id'];
        $product = wc_get_product($id);

        if (!$product) {
            return new \WP_REST_Response([
                'success' => false,
                'message' => __('Product not found', 'variation-hub'),
            ], 404);
        }

        // Get product images
        $images = [];
        $product_images = $product->get_gallery_image_ids();
        
        // Add featured image first
        if ($product->get_image_id()) {
            $images[] = [
                'id' => $product->get_image_id(),
                'src' => wp_get_attachment_image_url($product->get_image_id(), 'full'),
                'thumbnail' => wp_get_attachment_image_url($product->get_image_id(), 'thumbnail'),
                'alt' => get_post_meta($product->get_image_id(), '_wp_attachment_image_alt', true),
            ];
        }

        // Add gallery images
        foreach ($product_images as $image_id) {
            $images[] = [
                'id' => $image_id,
                'src' => wp_get_attachment_image_url($image_id, 'full'),
                'thumbnail' => wp_get_attachment_image_url($image_id, 'thumbnail'),
                'alt' => get_post_meta($image_id, '_wp_attachment_image_alt', true),
            ];
        }

        return new \WP_REST_Response([
            'success' => true,
            'data' => [
                'id' => $product->get_id(),
                'name' => $product->get_name(),
                'images' => $images,
            ],
        ], 200);
    }

    /**
     * Autocomplete products (parent names + SKUs)
     *
     * @param \WP_REST_Request $request Request object
     * @return \WP_REST_Response
     */
    public function autocomplete_products($request) {
        $query = $request->get_param('q');
        
        if (strlen($query) < 3) {
            return new \WP_REST_Response([
                'success' => false,
                'message' => __('Minimum 3 characters required', 'variation-hub'),
            ], 400);
        }

        global $wpdb;
        
        // Get unique parent products that have variations matching the search
        $sql = "
            SELECT DISTINCT p.ID, p.post_title
            FROM {$wpdb->posts} p
            INNER JOIN {$wpdb->posts} v ON v.post_parent = p.ID
            WHERE p.post_type = 'product'
            AND v.post_type = 'variation'
            AND v.post_status = 'publish'
            AND (
                p.post_title LIKE %s
                OR p.ID IN (
                    SELECT DISTINCT post_id 
                    FROM {$wpdb->postmeta}
                    WHERE meta_key = '_sku'
                    AND meta_value LIKE %s
                )
            )
            LIMIT 10
        ";
        
        $search_term = '%' . $wpdb->esc_like($query) . '%';
        // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- $sql is prepared with $wpdb->prepare() below
        $results = $wpdb->get_results($wpdb->prepare($sql, $search_term, $search_term));
        
        $suggestions = [];
        foreach ($results as $row) {
            $product = wc_get_product($row->ID);
            if ($product) {
                $suggestions[] = [
                    'label' => $row->post_title,
                    'sublabel' => $product->get_sku() ?: 'SKU: -',
                    'value' => $row->post_title,
                ];
            }
        }
        
        return new \WP_REST_Response([
            'success' => true,
            'data' => $suggestions,
        ], 200);
    }

    /**
     * Autocomplete attributes (attribute names and values)
     *
     * @param \WP_REST_Request $request Request object
     * @return \WP_REST_Response
     */
    public function autocomplete_attributes($request) {
        $query = strtolower($request->get_param('q'));
        
        if (strlen($query) < 1) {
            return new \WP_REST_Response([
                'success' => false,
                'message' => __('Minimum 1 character required', 'variation-hub'),
            ], 400);
        }

        global $wpdb;
        
        $suggestions = [];
        
        // Search in global attributes
        $attributes = wc_get_attribute_taxonomies();
        foreach ($attributes as $attribute) {
            $attr_name = $attribute->attribute_label;
            $attr_slug = 'pa_' . $attribute->attribute_name;
            
            // Check if attribute name matches
            if (stripos($attr_name, $query) !== false) {
                $suggestions[] = [
                    'label' => $attr_name . ': *',
                    'sublabel' => 'Attribútum neve',
                    'value' => $attr_name,
                ];
            }
            
            // Search in attribute terms (values)
            $terms = get_terms([
                'taxonomy' => $attr_slug,
                'hide_empty' => false,
                'search' => $query,
                'number' => 5,
            ]);
            
            if (!is_wp_error($terms)) {
                foreach ($terms as $term) {
                    $suggestions[] = [
                        'label' => $term->name,
                        'sublabel' => $attr_name,
                        'value' => $term->name,
                    ];
                }
            }
        }
        
        // Limit to 10 results
        $suggestions = array_slice($suggestions, 0, 10);
        
        return new \WP_REST_Response([
            'success' => true,
            'data' => $suggestions,
        ], 200);
    }

    /**
     * Get collection params
     *
     * @return array
     */
    public function get_collection_params() {
        return [
            'offset' => [
                'description' => __('Offset', 'variation-hub'),
                'type' => 'integer',
                'default' => 0,
                'minimum' => 0,
            ],
            'limit' => [
                'description' => __('Limit', 'variation-hub'),
                'type' => 'integer',
                'default' => 100,
                'minimum' => 1,
                'maximum' => 500,
            ],
            'search' => [
                'description' => __('Search term', 'variation-hub'),
                'type' => 'string',
            ],
            'parent_id' => [
                'description' => __('Parent product ID', 'variation-hub'),
                'type' => 'integer',
            ],
        ];
    }
    
    /**
     * Get variations grouped by parent products
     *
     * @param \WP_REST_Request $request Request object
     * @return \WP_REST_Response
     */
    private function get_items_grouped($request) {
        $params = $request->get_params();
        
        // Get all parent products (variable products)
        $parent_args = [
            'type' => 'variable',
            'status' => 'publish',
            'limit' => -1, // Get all (we'll implement pagination later if needed)
        ];
        
        // Add search filter for parent names
        if (!empty($params['search'])) {
            $parent_args['s'] = sanitize_text_field($params['search']);
        }
        
        $parent_products = wc_get_products($parent_args);
        
        $parents_data = [];
        $filter_attributes = !empty($params['attributes']) ? strtolower(sanitize_text_field($params['attributes'])) : '';
        
        foreach ($parent_products as $parent) {
            // Get all variations for this parent
            $variation_ids = $parent->get_children();
            
            if (empty($variation_ids)) {
                continue; // Skip parents without variations
            }
            
            $variations_data = [];
            $has_matches = false;
            $matched_variation_ids = [];
            
            foreach ($variation_ids as $variation_id) {
                $variation = wc_get_product($variation_id);
                
                if (!$variation) {
                    continue;
                }
                
                // Check if variation matches filter
                $matched = false;
                
                if (!empty($filter_attributes)) {
                    $variation_attrs = $variation->get_attributes();
                    
                    foreach ($variation_attrs as $key => $value) {
                        if (stripos(strtolower($value), $filter_attributes) !== false) {
                            $matched = true;
                            $has_matches = true;
                            $matched_variation_ids[] = $variation_id;
                            break;
                        }
                    }
                } else {
                    // ✅ NO FILTER: All variations are matched (for "Találatok bejelölése" to work)
                    $matched = true;
                    $has_matches = true;
                }
                
                // Prepare variation data
                $variation_data = $this->prepare_item_for_response($variation, $request);
                $variation_data['matched'] = $matched; // Mark if matched filter
                
                $variations_data[] = $variation_data;
            }
            
            // Only include parent if it has variations (and matches filter if applied)
            if (!empty($filter_attributes) && !$has_matches) {
                continue; // Skip parent if no variations match
            }
            
            // Prepare parent data
            $parent_image_id = $parent->get_image_id();
            $parent_image_url = $parent_image_id ? wp_get_attachment_image_url($parent_image_id, 'thumbnail') : '';
            
            $parents_data[] = [
                'id' => $parent->get_id(),
                'name' => $parent->get_name(),
                'image_url' => $parent_image_url,
                'variation_count' => count($variation_ids),
                'has_matches' => $has_matches,
                'matched_variation_ids' => $matched_variation_ids,
                'variations' => $variations_data,
            ];
        }
        
        // Get valid tax classes for dropdown
        $tax_classes = WC_Tax::get_tax_class_slugs();
        
        // Add 'parent' and empty string (standard) as special options
        $tax_class_options = array_merge(['parent', ''], $tax_classes);
        
        return new \WP_REST_Response([
            'success' => true,
            'data' => [
                'parents' => $parents_data,
                'total_parents' => count($parents_data),
                'mode' => 'grouped',
                'tax_class_options' => $tax_class_options, // Available tax classes
            ],
        ], 200);
    }
}
