<?php
if (!defined('WPINC')) {
    die;
}

class SeekMake_WooCommerce {

    /**
     * Option key for the hidden WooCommerce product ID.
     */
    const PRODUCT_OPTION_KEY = 'seekmake_wc_product_id';

    /**
     * Fields to display in the WooCommerce cart under the item name.
     * Any new field sent by SeekMake will also be saved to order meta automatically.
     */
    private $cart_display_fields = array(
        'material'   => 'Material',
        'technology' => 'Technology',
        'color'      => 'Color',
        'infill'     => 'Infill',
        'precision'  => 'Precision',
        'lead_time'  => 'Lead Time',
    );

    /**
     * Fields to hide from cart/order display (internal use only).
     */
    private $hidden_fields = array(
        'filelink',
        'filename',
        'priceperpiece',
        'productprice',
        'quantity',
        'type',
    );

    public function init() {
        $this->define_hooks();
    }

    private function define_hooks() {
        // AJAX handlers — both logged-in and guest users
        add_action('wp_ajax_seekmake_wc_add_to_cart', array($this, 'ajax_add_to_cart'));
        add_action('wp_ajax_nopriv_seekmake_wc_add_to_cart', array($this, 'ajax_add_to_cart'));

        // Override price in cart with the custom quoted price
        add_action('woocommerce_before_calculate_totals', array($this, 'override_cart_item_price'), 20, 1);

        // Show custom metadata under item name in cart (dynamic)
        add_filter('woocommerce_get_item_data', array($this, 'display_cart_item_data'), 10, 2);

        // Persist all metadata to the WooCommerce order on checkout
        add_action('woocommerce_checkout_create_order_line_item', array($this, 'save_order_item_meta'), 10, 4);

        // Override product name in cart with the file name
        add_filter('woocommerce_cart_item_name', array($this, 'override_cart_item_name'), 10, 3);

        // Override product thumbnail if a 3D preview is available
        add_filter('woocommerce_cart_item_thumbnail', array($this, 'override_cart_item_thumbnail'), 10, 3);
    }

    /**
     * AJAX handler: Add SeekMake quote items to the WooCommerce cart.
     *
     * Receives a JSON-encoded items array from the frontend matching the
     * EDITOR_PAY_NOW_EXTERNAL_CHECKOUT event payload from the SeekMake iframe.
     *
     * All item data is stored dynamically — no plugin update needed when
     * SeekMake adds new fields to the payload.
     */
    public function ajax_add_to_cart() {
        if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'seekmake_wc_cart')) {
            wp_send_json_error(array('message' => __('Security check failed.', 'seekmake')), 403);
        }

        // Parse the items array sent as JSON string
        $items_raw = isset($_POST['items']) ? wp_unslash($_POST['items']) : '[]';
        $items = json_decode($items_raw, true);

        if (empty($items) || !is_array($items)) {
            wp_send_json_error(array('message' => __('No items provided.', 'seekmake')));
        }

        $currency = isset($_POST['currency']) ? sanitize_text_field(wp_unslash($_POST['currency'])) : 'USD';
        $subtotal = isset($_POST['subtotal']) ? floatval($_POST['subtotal']) : 0;

        // Get or create the hidden WooCommerce product
        $product_id = $this->get_or_create_product();

        if (!$product_id || is_wp_error($product_id)) {
            wp_send_json_error(array('message' => __('Failed to create product. Please try again.', 'seekmake')));
        }

        $added_count = 0;

        foreach ($items as $item) {
            $item_type = isset($item['type']) ? sanitize_text_field($item['type']) : 'print';
            $price     = isset($item['pricePerPiece']) ? floatval($item['pricePerPiece']) : 0;
            $quantity  = isset($item['quantity']) ? absint($item['quantity']) : 1;

            if ($price <= 0 || $quantity < 1) {
                continue;
            }

            // Sanitize all item data dynamically
            $sanitized_item = $this->sanitize_item_data($item);

            if ($item_type === 'startup_cost') {
                $cart_item_data = array(
                    'seekmake_custom_price' => $price,
                    'seekmake_item_name'    => __('Startup / Setup Fee', 'seekmake'),
                    'seekmake_is_fee'       => true,
                    'seekmake_item_data'    => $sanitized_item,
                    'seekmake_currency'     => $currency,
                    'seekmake_unique_key'   => md5(microtime() . wp_rand()),
                );
            } else {
                $file_name = isset($item['fileName']) ? sanitize_text_field($item['fileName']) : __('Custom 3D Print', 'seekmake');

                $cart_item_data = array(
                    'seekmake_custom_price' => $price,
                    'seekmake_item_name'    => $file_name,
                    'seekmake_item_data'    => $sanitized_item,
                    'seekmake_currency'     => $currency,
                    'seekmake_unique_key'   => md5(microtime() . wp_rand()),
                );
            }

            $cart_item_key = WC()->cart->add_to_cart($product_id, $quantity, 0, array(), $cart_item_data);

            if ($cart_item_key) {
                $added_count++;
            }
        }

        if ($added_count === 0) {
            wp_send_json_error(array('message' => __('Failed to add items to cart.', 'seekmake')));
        }

        wp_send_json_success(array(
            'message'    => sprintf(
                _n('%d item added to cart!', '%d items added to cart!', $added_count, 'seekmake'),
                $added_count
            ),
            'cart_count' => WC()->cart->get_cart_contents_count(),
            'cart_url'   => wc_get_cart_url(),
        ));
    }

    /**
     * Sanitize all fields in an item dynamically.
     * Handles strings, numbers, booleans, and URLs.
     */
    private function sanitize_item_data($item) {
        $sanitized = array();

        foreach ($item as $key => $value) {
            $key = sanitize_key($key);

            if (is_array($value)) {
                $sanitized[$key] = $this->sanitize_item_data($value);
            } elseif (is_numeric($value)) {
                $sanitized[$key] = is_float($value + 0) ? floatval($value) : intval($value);
            } elseif (is_bool($value)) {
                $sanitized[$key] = $value;
            } elseif (filter_var($value, FILTER_VALIDATE_URL)) {
                $sanitized[$key] = esc_url_raw($value);
            } else {
                $sanitized[$key] = sanitize_text_field($value);
            }
        }

        return $sanitized;
    }

    /**
     * Get existing hidden product ID or create a new one.
     */
    private function get_or_create_product() {
        $product_id = get_option(self::PRODUCT_OPTION_KEY, 0);

        if ($product_id) {
            $product = wc_get_product($product_id);
            if ($product && $product->get_status() !== 'trash') {
                return $product_id;
            }
        }

        $product = new WC_Product_Simple();
        $product->set_name(__('SeekMake 3D Print Service', 'seekmake'));
        $product->set_status('private');
        $product->set_catalog_visibility('hidden');
        $product->set_price(0);
        $product->set_regular_price(0);
        $product->set_sold_individually(false);
        $product->set_manage_stock(false);
        $product->set_weight(0.5);
        $product->save();

        $product_id = $product->get_id();

        if ($product_id) {
            update_option(self::PRODUCT_OPTION_KEY, $product_id);
        }

        return $product_id;
    }

    /**
     * Override the cart item price and name with custom quoted values.
     *
     * Sets both the price and product name on the WC_Product data object.
     * This is essential for WooCommerce Blocks (React-based cart/checkout)
     * which read from the Store API and ignore classic PHP display filters
     * like woocommerce_cart_item_name.
     */
    public function override_cart_item_price($cart) {
        if (is_admin() && !defined('DOING_AJAX')) {
            return;
        }

        if (did_action('woocommerce_before_calculate_totals') >= 2) {
            return;
        }

        foreach ($cart->get_cart() as $cart_item) {
            if (isset($cart_item['seekmake_custom_price'])) {
                $cart_item['data']->set_price(floatval($cart_item['seekmake_custom_price']));
            }

            // Override product name so it appears correctly in both
            // classic cart (display filter fallback) and Blocks cart (Store API).
            if (!empty($cart_item['seekmake_item_name'])) {
                $cart_item['data']->set_name(sanitize_text_field($cart_item['seekmake_item_name']));
            }
        }
    }

    /**
     * Display custom metadata under the item name in the cart page.
     * Uses $cart_display_fields for known fields, and also shows any new
     * fields dynamically so no plugin update is needed.
     */
    public function display_cart_item_data($item_data, $cart_item) {
        if (empty($cart_item['seekmake_item_data'])) {
            return $item_data;
        }

        $raw = $cart_item['seekmake_item_data'];

        // Show known display fields first (in order)
        foreach ($this->cart_display_fields as $key => $label) {
            if (!empty($raw[$key])) {
                $item_data[] = array(
                    'key'   => __($label, 'seekmake'),
                    'value' => sanitize_text_field($raw[$key]),
                );
            }
        }

        // Show any NEW fields that aren't in our known lists (future-proof)
        $all_known = array_merge(array_keys($this->cart_display_fields), $this->hidden_fields);
        foreach ($raw as $key => $value) {
            if (!in_array($key, $all_known) && !is_array($value) && !empty($value)) {
                $label = ucwords(str_replace('_', ' ', $key));
                $item_data[] = array(
                    'key'   => $label,
                    'value' => sanitize_text_field($value),
                );
            }
        }

        return $item_data;
    }

    /**
     * Save ALL metadata to the order line item on checkout.
     * Stores everything dynamically so the store owner and SeekMake
     * can see all details in the WooCommerce order admin.
     */
    public function save_order_item_meta($item, $cart_item_key, $values, $order) {
        // Save the item name
        if (!empty($values['seekmake_item_name'])) {
            $item->add_meta_data(__('Item Name', 'seekmake'), sanitize_text_field($values['seekmake_item_name']), true);
            $item->set_name(sanitize_text_field($values['seekmake_item_name']));
        }

        // Save fee flag
        if (!empty($values['seekmake_is_fee'])) {
            $item->add_meta_data(__('Type', 'seekmake'), __('Setup Fee', 'seekmake'), true);
        }

        // Save all item data dynamically
        if (!empty($values['seekmake_item_data']) && is_array($values['seekmake_item_data'])) {
            foreach ($values['seekmake_item_data'] as $key => $value) {
                // Skip internal/numeric fields (keys are lowercased by sanitize_key)
                if (in_array($key, array('priceperpiece', 'quantity', 'type'))) {
                    continue;
                }

                if (!empty($value) && !is_array($value)) {
                    $label = ucwords(str_replace('_', ' ', sanitize_key($key)));
                    $item->add_meta_data($label, sanitize_text_field($value), true);
                }
            }
        }

        // Save currency
        if (!empty($values['seekmake_currency'])) {
            $item->add_meta_data(__('Currency', 'seekmake'), sanitize_text_field($values['seekmake_currency']), true);
        }
    }

    /**
     * Override the product name in the cart with the file name.
     */
    public function override_cart_item_name($name, $cart_item, $cart_item_key) {
        if (!empty($cart_item['seekmake_item_name'])) {
            return esc_html($cart_item['seekmake_item_name']);
        }
        return $name;
    }

    /**
     * Override the product thumbnail in the cart if a 3D preview image is available.
     */
    public function override_cart_item_thumbnail($thumbnail, $cart_item, $cart_item_key) {
        if (!empty($cart_item['seekmake_thumbnail'])) {
            $alt = esc_attr($cart_item['seekmake_item_name'] ?? '3D Print');
            return '<img src="' . esc_url($cart_item['seekmake_thumbnail']) . '" alt="' . $alt . '" class="seekmake-cart-thumbnail" style="width:70px;height:70px;object-fit:cover;" />';
        }
        return $thumbnail;
    }
}
