<?php
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController;

require_once plugin_dir_path(dirname(__FILE__)) . 'vendor/autoload.php';

class OrderPickingApp_Admin
{
    public function __construct()
    {
        // OLD
        add_action('manage_edit-shop_order_columns', array($this, 'add_orderpickingapp_order_column'), 10, 1);
        add_action('manage_shop_order_posts_custom_column', array($this, 'add_orderpickingapp_order_column_value'), 10, 2);
        add_filter('handle_bulk_actions-edit-shop_order', array($this, 'orderpickingapp_handle_bulk_actions_shop_order'), 20, 3 );
        add_action('woocommerce_update_order', array($this, 'save_orderpickingapp_order_meta_box_data'));

        // HPOS
        add_filter('manage_woocommerce_page_wc-orders_columns', array($this, 'add_orderpickingapp_order_column'), 10, 1);
        add_action('manage_woocommerce_page_wc-orders_custom_column', array($this, 'add_orderpickingapp_order_column_value'), 10, 2);
        add_filter('bulk_actions-woocommerce_page_wc-orders', array($this, 'orderpickingapp_register_bulk_action') );
        add_filter('handle_bulk_actions-woocommerce_page_wc-orders', array($this, 'orderpickingapp_handle_bulk_actions_shop_order'), 20, 3 );
        add_filter('bulk_actions-edit-shop_order', array($this, 'orderpickingapp_register_bulk_action') );

        add_action('add_meta_boxes', array($this, 'orderpickingapp_order_meta_boxes'));
        add_action('save_post_shop_order', array($this, 'save_orderpickingapp_order_meta_box_data'));

        $plugin_basename = OPA_PLUGIN_BASENAME;
        add_filter( "plugin_action_links_$plugin_basename", array( $this, 'orderpickingapp_plugin_add_settings_link') );

        add_action('woocommerce_product_options_general_product_data', array( $this, 'orderpickingapp_add_costs_price_field_to_general_tab'));
        add_action('woocommerce_product_options_inventory_product_data', array( $this, 'orderpickingapp_add_supplier_sku_field_to_inventory_tab'));
        add_action('woocommerce_admin_process_product_object', array( $this, 'save_orderpickingapp_product_fields'));

        add_action('woocommerce_product_after_variable_attributes', array( $this, 'orderpickingapp_add_supplier_sku_field_to_variations'), 10, 3);
        add_action('woocommerce_save_product_variation', array( $this, 'orderpickingapp_add_supplier_sku_field_for_variations'), 10, 2);
        add_action('woocommerce_single_product_summary', array( $this, 'orderpickingapp_enqueue_supplier_sku_script'));

        add_action('wp_ajax_get_stock_mutations', array( $this, 'orderpickingapp_get_stock_mutations') );
        add_action('wp_ajax_export_stock_mutations', array( $this, 'orderpickingapp_export_stock_mutations') );
        add_action('wp_ajax_download_picklist', array( $this, 'orderpickingapp_download_picklist') );

        add_action('wp_dashboard_setup', array( $this, 'orderpickingapp_dashboard_widget'));

        add_filter('manage_edit-product_columns', array( $this, 'orderpickingapp_manage_edit_product_columns'));
        add_action('manage_product_posts_custom_column', array( $this, 'orderpickingapp_manage_product_posts_custom_column'), 10, 2);
        add_filter('bulk_actions-edit-product', array( $this, 'orderpickingapp_bulk_actions_edit_product'));
        add_filter('handle_bulk_actions-edit-product', array( $this, 'orderpickingapp_handle_bulk_actions_edit_product'), 10, 3);

        add_action('admin_post_orderpickingapp_barcode_img_download', array($this, 'orderpickingapp_barcode_img_download'));
        add_action('admin_post_orderpickingapp_barcode_img_print',    array($this, 'orderpickingapp_barcode_img_print'));
        add_action('admin_post_orderpickingapp_order_label_pdf',      array($this, 'orderpickingapp_order_label_pdf'));

        add_action('admin_head',    array($this, 'orderpickingapp_admin_order_notes_styling'));
        add_action( 'admin_enqueue_scripts', array( $this, 'orderpickingapp_enqueue_assets' ) );

        add_action('woocommerce_after_order_itemmeta', array( $this, 'orderpickingapp_show_order_item_note' ), 10, 2 );
    }

    public function orderpickingapp_show_order_item_note($item_id, $item) {
        $note_meta_key = apply_filters(
            'orderpickingapp_order_item_note_meta_key',
            'orderpickingapp_order_item_note',
            null,
            $item->get_order()
        );

        $note = $item->get_meta($note_meta_key);

        if (!empty($note)) {
            echo '<div style="margin-top:8px;padding:8px;background:#fff8e5;border-left:4px solid #f0b429;">';
            echo '<strong>Product note:</strong><br>';
            echo nl2br(esc_html($note));
            echo '</div>';
        }
    }

    public function orderpickingapp_enqueue_assets( $hook ) {

        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
        $page = sanitize_key( $page );

        // Laad op eigen plugin pagina OF WooCommerce orders/product pagina
        $current_screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;

        $is_orders_screen = false;
        $is_product_edit_screen = false;

        if ( $current_screen ) {
            $is_orders_screen =
                // HPOS orders scherm
                'woocommerce_page_wc-orders' === $current_screen->id ||

                // Oude CPT orders scherm fallback
                'edit-shop_order' === $current_screen->id;

            $is_product_edit_screen =
                // WooCommerce product bewerken
                'product' === $current_screen->id;
        }

        if ( 'orderpickingapp-panel' !== $page && ! $is_orders_screen && ! $is_product_edit_screen ) {
            return;
        }

        wp_enqueue_style( 'dashicons' );
        wp_enqueue_style(
            'orderpickingapp-admin',
            OPA_PLUGIN_URL . 'admin/css/orderpickingapp.css',
            array(),
            filemtime( OPA_PLUGIN_DIR . 'admin/css/orderpickingapp.css' ),
        );

        wp_enqueue_script(
            'orderpickingapp-bootstrap',
            OPA_PLUGIN_URL . 'admin/js/bootstrap.min.js',
            array( 'jquery' ),
            filemtime( OPA_PLUGIN_DIR . 'admin/js/bootstrap.min.js' ),
            true
        );

        wp_enqueue_script( 'jquery-ui-core' );
        wp_enqueue_script( 'jquery-ui-sortable' );


        wp_enqueue_script(
            'orderpickingapp-admin',
            OPA_PLUGIN_URL . 'admin/js/admin.js',
            array( 'jquery', 'jquery-ui-core', 'jquery-ui-sortable' ),
            filemtime( OPA_PLUGIN_DIR . 'admin/js/admin.js' ),
            true
        );

        wp_localize_script('orderpickingapp-admin', 'appData', [
            'ajaxurl' => admin_url('admin-ajax.php'),
            'nonce'   => wp_create_nonce('orderpickingapp_nonce')
        ]);

        wp_enqueue_script(
            'orderpickingapp-chart',
            OPA_PLUGIN_URL . 'admin/js/chart.min.js',
            array(),
            filemtime( OPA_PLUGIN_DIR . 'admin/js/chart.min.js' ),
            true
        );
    }

    private function verify_orderpickingapp_bulk_posts_nonce() {
        return isset( $_REQUEST['_wpnonce'] ) && wp_verify_nonce(
                sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ),
                'bulk-posts'
            );
    }

    public function orderpickingapp_admin_order_notes_styling() {
        $screen = get_current_screen();
        if (!$screen || $screen->post_type !== 'shop_order') return;
        ?>
        <style>
            #woocommerce-order-notes .order_notes li.orderpickingapp-note .note_content::after{
                border-color: #2196f3 transparent;
            }
            #woocommerce-order-notes .order_notes li.orderpickingapp-note .note_content{
                background: #fff;
                border: 1px solid #2196f3;
                border-radius: 5px;
            }
        </style>

        <script>
            document.addEventListener('DOMContentLoaded', function () {
                const notes = document.querySelectorAll('#woocommerce-order-notes .order_notes li');

                notes.forEach(li => {
                    const content = li.querySelector('.note_content');
                    if (!content) return;

                    const text = content.textContent.trim();
                    if (text.startsWith('Order Picking App')) {
                        li.classList.add('orderpickingapp-note');
                    }
                });
            });
        </script>
        <?php
    }


    public function orderpickingapp_manage_edit_product_columns($cols)
    {
        $cols['orderpickingapp_barcode_img'] = __('Barcode (PNG/Print)', 'order-picking-app');
        return $cols;
    }

    public function orderpickingapp_manage_product_posts_custom_column($column, $post_id)
    {
        if ($column !== 'orderpickingapp_barcode_img') return;
        if (!current_user_can('manage_woocommerce')) { return; }

        $print_url = wp_nonce_url(
            admin_url('admin-post.php?action=orderpickingapp_barcode_img_print&product_id='.(int)$post_id),
            'orderpickingapp_barcode_img_nonce_action',
            'orderpickingapp_barcode_img_nonce'
        );
        $download_url = wp_nonce_url(
            admin_url('admin-post.php?action=orderpickingapp_barcode_img_download&product_id='.(int)$post_id),
            'orderpickingapp_barcode_img_nonce_action',
            'orderpickingapp_barcode_img_nonce'
        );

        echo '<a class="button" href="'.esc_url($print_url).'">'.esc_html__('Print', 'order-picking-app').'</a> ';
        echo '<a class="button" href="'.esc_url($download_url).'">'.esc_html__('PNG', 'order-picking-app').'</a>';
    }

    public function orderpickingapp_bulk_actions_edit_product($actions)
    {
        $actions['orderpickingapp_barcode_img_bulk_print_ean'] = __('Print barcodes (EAN/SKU)', 'order-picking-app');
        $actions['orderpickingapp_barcode_img_bulk_print_id']  = __('Print barcodes (ID)', 'order-picking-app');

        return $actions;
    }

    public function orderpickingapp_handle_bulk_actions_edit_product($redirect_to, $action, $post_ids)
    {
        if (!in_array($action, ['orderpickingapp_barcode_img_bulk_print_ean', 'orderpickingapp_barcode_img_bulk_print_id'], true)) {
            return $redirect_to;
        }

        if ( ! $this->verify_orderpickingapp_bulk_posts_nonce() ) {
            return $redirect_to;
        }

        if (!current_user_can('manage_woocommerce')) {
            return $redirect_to;
        }

        $barcode_type = ($action === 'orderpickingapp_barcode_img_bulk_print_id') ? 'id' : 'ean';

        $url = wp_nonce_url(
            add_query_arg([
                'action'       => 'orderpickingapp_barcode_img_print',
                'post_ids'     => implode(',', array_map('intval', (array) $post_ids)),
                'barcode_type' => $barcode_type,
            ], admin_url('admin-post.php')),
            'orderpickingapp_barcode_img_nonce_action',
            'orderpickingapp_barcode_img_nonce'
        );

        wp_safe_redirect(html_entity_decode($url));
        exit;
    }

    // EAN of SKU ophalen
    private function orderpickingapp_img_get_value_for_product(int $product_id, string $ean_meta_key = '_alg_ean'): ?string {
        $ean = get_post_meta($product_id, $ean_meta_key, true);
        if (!$ean) {
            $product = wc_get_product($product_id);
            if ($product) $ean = $product->get_sku();
        }
        $ean = is_string($ean) ? trim($ean) : '';
        return $ean !== '' ? $ean : null;
    }

    private function orderpickingapp_img_normalize_type(string $value ): array {
        return ['type' => 'CODE128', 'value' => $value];
    }

// PNG data genereren met Picqer
    private function orderpickingapp_img_generate_png_data(string $value, int $scale = 3, int $height = 80): string {
        if (!class_exists('\Picqer\Barcode\BarcodeGeneratorPNG')) {
            require_once plugin_dir_path(dirname(__FILE__)) . 'vendor/autoload.php';
        }

        $gen = new \Picqer\Barcode\BarcodeGeneratorPNG();
        $t   = \Picqer\Barcode\BarcodeGeneratorPNG::TYPE_CODE_128;

        return $gen->getBarcode($value, $t, max(1,$scale), max(20,$height));
    }

    // PNG opslaan in uploads/orderpickingapp-barcodes/ en pad+url teruggeven
    private function orderpickingapp_img_save_png_for_product(int $product_id, string $value, int $scale = 3, int $height = 80): array {
        $upload = wp_upload_dir();
        if ( ! empty( $upload['error'] ) ) {
            wp_die( esc_html( 'Uploads-map niet beschikbaar: ' . $upload['error'] ), '', array( 'response' => 500 ) );
        }

        $dir  = trailingslashit($upload['basedir']).'orderpickingapp-barcodes';
        $urlb = trailingslashit($upload['baseurl']).'orderpickingapp-barcodes';
        if ( ! wp_mkdir_p( $dir ) ) {
            wp_die( esc_html( 'Kan map niet aanmaken: ' . $dir ), '', array( 'response' => 500 ) );
        }

        // Genereer en schrijf PNG
        $png  = $this->orderpickingapp_img_generate_png_data($value, 3, 80);
        $file = 'product-'.$product_id.'-'.time().'.png';
        $path = trailingslashit($dir).$file;
        file_put_contents($path, $png);

        return ['path' => $path, 'url' => trailingslashit($urlb).$file, 'filename' => $file];
    }

    // Single PNG download
    public function orderpickingapp_barcode_img_download() {
        if (!current_user_can('manage_woocommerce')) wp_die('Forbidden', 403);
        if (!isset($_GET['orderpickingapp_barcode_img_nonce']) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['orderpickingapp_barcode_img_nonce'] ) ), 'orderpickingapp_barcode_img_nonce_action' )) {
            wp_die('Bad nonce', 400);
        }

        $pid = isset( $_GET['product_id'] ) ? absint( wp_unslash( $_GET['product_id'] ) ) : 0;
        if ($pid <= 0) wp_die('Geen product_id', 400);

        $val = $this->orderpickingapp_img_get_value_for_product($pid, '_alg_ean');
        if (!$val) wp_die('Geen EAN/SKU gevonden.', 400);

        $norm  = $this->orderpickingapp_img_normalize_type($val);
        $file  = $this->orderpickingapp_img_save_png_for_product($pid, $norm['value']);

        $binary = file_get_contents($file['path']);

        $binary = $this->orderpickingapp_img_compose_labeled_png($binary, $norm['value']);
        $fname = 'product-'.$pid.'-labeled.png';

        header('Content-Type: image/png');
        header('Content-Disposition: attachment; filename="'.$fname.'"');
        echo $binary; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Binary PNG output.
        exit;
    }

    public function orderpickingapp_barcode_img_print() {
        if (!current_user_can('manage_woocommerce')) {
            wp_die('Forbidden', 403);
        }

        if (
            !isset($_GET['orderpickingapp_barcode_img_nonce']) ||
            ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['orderpickingapp_barcode_img_nonce'] ) ), 'orderpickingapp_barcode_img_nonce_action' )
        ) {
            wp_die('Bad nonce', 400);
        }

        $barcode_type = isset($_GET['barcode_type'])
            ? sanitize_text_field(wp_unslash($_GET['barcode_type']))
            : 'ean';

        $ids = [];
        if (isset($_GET['product_id'])) {
            $ids = [ absint( wp_unslash( $_GET['product_id'] ) ) ];
        } elseif (!empty($_GET['post_ids'])) {
            $ids = array_filter(array_map('intval', explode( ',', sanitize_text_field( wp_unslash( $_GET['post_ids'] ) ) )));
        }

        if (empty($ids)) {
            wp_die('Geen producten opgegeven.', 400);
        }

        $images = [];

        foreach ($ids as $pid) {
            $product = wc_get_product($pid);
            if (!$product) {
                continue;
            }

            $title = $product->get_name();

            if ($barcode_type === 'id') {
                $barcode_value = (string) $pid;
                $label_top     = $title;
                $label_bottom  = (string) $pid;
            } else {
                $val = $this->orderpickingapp_img_get_value_for_product($pid, '_alg_ean');
                if (!$val) {
                    continue;
                }

                $norm = $this->orderpickingapp_img_normalize_type($val);
                $barcode_value = $norm['value'];
                $label_top     = $title;
                $label_bottom  = $barcode_value;
            }

            $f = $this->orderpickingapp_img_save_png_for_product($pid, $barcode_value);

            $images[] = [
                'url'          => $f['url'],
                'id'           => $pid,
                'barcode_type' => $barcode_type,
                'barcode'      => $barcode_value,
                'label_top'    => $label_top,
                'label_bottom' => $label_bottom,
            ];
        }

        if (empty($images)) {
            wp_die(
                $barcode_type === 'id'
                    ? 'Geen geldige producten gevonden.'
                    : 'Geen geldige EAN/SKU waarden gevonden.',
                400
            );
        }

        ?>
        <!doctype html>
        <html lang="en">
        <head>
            <meta charset="utf-8">
            <title>Product barcodes</title>
            <style>
                body { margin: 16px; font: 14px/1.4 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif; }
                .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 16px; }
                .item { border: 1px solid #ddd; padding: 12px; text-align: center; break-inside: avoid; }
                @media print { .controls { display:none } .item { border: none; } body { margin: 0; } }
                .title { font-weight: 600; margin-bottom: 6px; font-size: 13px; }
                .val   { margin-top: 8px; font-size: 12px; color: #333; letter-spacing: 1px; }
            </style>
            <script>
                function closeWindow() {
                    if (window.opener && !window.opener.closed) {
                        window.close();
                        return;
                    }
                    if (history.length > 1) {
                        history.back();
                    } else {
                        window.location.href = '<?php echo esc_js(admin_url('edit.php?post_type=product')); ?>';
                    }
                }
            </script>
        </head>
        <body>
        <div class="controls">
            <h1>Product barcodes</h1>
            <p>
                <button onclick="window.print()">Print</button>
                <button onclick="closeWindow()">Sluiten</button>
            </p>
        </div>
        <div class="grid">
            <?php foreach ($images as $img): ?>
                <div class="item">
                    <?php if ($img['label_top'] !== ''): ?>
                        <div class="title"><?php echo esc_html($img['label_top']); ?></div>
                    <?php endif; ?>

                    <img src="<?php echo esc_url($img['url']); ?>" alt="barcode" style="max-width:100%; height:auto;" />

                    <?php if ($img['label_bottom'] !== ''): ?>
                        <div class="val"><?php echo esc_html($img['label_bottom']); ?></div>
                    <?php endif; ?>
                </div>
            <?php endforeach; ?>
        </div>
        <script>window.addEventListener('load', function(){ window.print(); });</script>
        </body>
        </html>
        <?php
        exit;
    }

    /**
     * Combineer barcode-PNG met tekstwaarde eronder in één PNG.
     * Gebruikt GD; met TTF (indien aanwezig) of imagestring fallback.
     */
    private function orderpickingapp_img_compose_labeled_png(string $barcodeBinary, string $value, int $padding = 10, int $textHeight = 18): string {
        $src = imagecreatefromstring($barcodeBinary);
        if (!$src) return $barcodeBinary;

        $w = imagesx($src);
        $h = imagesy($src);

        // Nieuwe hoogte: barcode + padding + tekst
        $newH = $h + $padding + $textHeight;
        $dst  = imagecreatetruecolor($w, $newH);

        // Wit canvas
        $white = imagecolorallocate($dst, 255,255,255);
        imagefilledrectangle($dst, 0, 0, $w, $newH, $white);

        // Plaats barcode boven
        imagecopy($dst, $src, 0, 0, 0, 0, $w, $h);
        imagedestroy($src);

        // Zwarte tekst
        $black = imagecolorallocate($dst, 0,0,0);

        // TTF als beschikbaar (mooier)
        $fontPath = __DIR__ . '/assets/DejaVuSans.ttf'; // zet hier evt. je eigen TTF neer
        $yBase    = $h + $padding + $textHeight - 4;

        if (file_exists($fontPath) && function_exists('imagettfbbox') && function_exists('imagettftext')) {
            $fontSize = 10; // pas aan naar wens
            $bbox = imagettfbbox($fontSize, 0, $fontPath, $value);
            $textW = abs($bbox[4] - $bbox[0]);
            $x = max(0, (int)(($w - $textW) / 2));
            imagettftext($dst, $fontSize, 0, $x, $yBase, $black, $fontPath, $value);
        } else {
            // Fallback: bitmap font
            $font = 3; // 1..5
            $textW = imagefontwidth($font) * strlen($value);
            $textH = imagefontheight($font);
            $x = max(0, (int)(($w - $textW) / 2));
            $y = $h + $padding + max(0, (int)(($textHeight - $textH)/2));
            imagestring($dst, $font, $x, $y, $value, $black);
        }

        ob_start();
        imagepng($dst);
        imagedestroy($dst);
        return ob_get_clean();
    }

    public function orderpickingapp_dashboard_widget() {
        wp_add_dashboard_widget(
            'orderpickingapp_widget',
            'Order Picking App',
            array( $this, 'orderpickingapp_widget_display')
        );
    }

    public function orderpickingapp_widget_display() {
        $orderpickingapp_apikey = get_option('orderpickingapp_apikey');
        if (isset($orderpickingapp_apikey) && !empty($orderpickingapp_apikey)) {
            $url = add_query_arg(
                array(
                    'token' => rawurlencode( $orderpickingapp_apikey ),
                ),
                rest_url( 'picking/v1/get-settings' )
            );

            $response = $this->orderpickingapp_remote_get_json(
                $url,
                array(
                    'Referer' => esc_url_raw( home_url() ),
                )
            );
        }

        if( isset($response['total_picking_orders']) ): ?>
            <style>
                .orderpickingapp-widget { display: flex; justify-content: space-around; align-items: center; margin-top: 10px; }
                .orderpickingapp-widget-item { position: relative; text-align: center; }
                .orderpickingapp-badge {
                    position: absolute;
                    top: 5px;
                    right: -10px;
                    background: #c00;
                    color: white;
                    border-radius: 12px;
                    padding: 2px 6px;
                    font-size: 12px;
                    font-weight: bold;
                }
                .orderpickingapp-icon {
                    font-size: 32px;
                    margin-top: 10px;
                }
                .orderpickingapp-blue { background: #00b2ff; }
            </style>
            <div class="orderpickingapp-widget">
                <div class="orderpickingapp-widget-item">
                    <div class="orderpickingapp-badge"><?php echo esc_html( absint( $response['total_picking_orders'] ) ); ?></div>
                    <div class="orderpickingapp-icon"><img src="<?php echo esc_url( OPA_PLUGIN_URL . 'admin/images/rectangle-barcode-regular.svg' ); ?>" width="25px" height="25px"/></div>
                    <p>Picking</p>
                </div>

                <div class="orderpickingapp-widget-item">
                    <div class="orderpickingapp-badge"><?php echo esc_html( absint( $response['total_packing_orders'] ) ); ?></div>
                    <div class="orderpickingapp-icon"><img src="<?php echo esc_url( OPA_PLUGIN_URL . 'admin/images/box-open-regular.svg' ); ?>" width="25px" height="25px"/></div>
                    <p>Packing</p>
                </div>

                <div class="orderpickingapp-widget-item">
                    <div class="orderpickingapp-badge orderpickingapp-blue"><?php echo esc_html( absint( $response['total_backorders'] ) ); ?></div>
                    <div class="orderpickingapp-icon"><img src="<?php echo esc_url( OPA_PLUGIN_URL . 'admin/images/hourglass-half-regular.svg' ); ?>" width="25px" height="25px"/></div>
                    <p>Backorder</p>
                </div>
            </div>
            <input type="hidden" id="orderpickingapp_nonce" value="<?php echo esc_attr( wp_create_nonce( 'orderpickingapp_nonce' ) ); ?>" />
            <button  style="width: 48%; float left; margin-bottom: 5px;" file_type="pdf" order_status="all" class="DownloadPicklist btn btn-primary">PDF picklist</button>
            <button style="width: 48%; float: right; margin-bottom: 5px;" file_type="pdf" order_status="backorders" class="DownloadPicklist btn btn-primary">PDF backorders</button>
            <button style="width: 48%; float left; margin-bottom: 5px;" file_type="pdf" order_status="summary"  class="DownloadPicklist btn btn-primary">PDF orders summary</button>
            <button style="width: 48%; float: right; margin-bottom: 5px;" file_type="csv" order_status="summary"  class="DownloadPicklist btn btn-primary">CSV orders summary</button>
            <button style="width: 48%; float left;" file_type="pdf" order_status="products"  class="DownloadPicklist btn btn-primary">PDF products summary</button>
            <button style="width: 48%; float: right;" file_type="csv" order_status="products"  class="DownloadPicklist btn btn-primary">CSV products summary</button>
        <?php endif;
    }

    public function orderpickingapp_download_picklist() {
        check_ajax_referer( 'orderpickingapp_nonce', 'security' );

        $orderpickingapp_apikey = get_option( 'orderpickingapp_apikey' );

        if ( empty( $orderpickingapp_apikey ) ) {
            wp_send_json_error( esc_html__( 'API key ontbreekt.', 'order-picking-app' ) );
        }

        $shop   = sanitize_text_field( get_option( 'orderpickingapp_subscription_id' ) );
        $status = isset( $_POST['status'] ) ? sanitize_key( wp_unslash( $_POST['status'] ) ) : '';
        $type   = isset( $_POST['type'] ) ? sanitize_key( wp_unslash( $_POST['type'] ) ) : '';

        $url = add_query_arg(
            array(
                'token'  => rawurlencode( $orderpickingapp_apikey ),
                'shop'   => rawurlencode( $shop ),
                'status' => $status,
                'type'   => $type,
            ),
            'https://orderpickingapp.com/wp-json/picking/v1/pickinglist'
        );

        // Haal data op via API.
        $response = $this->orderpickingapp_remote_get_json(
            $url,
            array(
                'Authorization' => 'Bearer ' . $orderpickingapp_apikey,
                'Referer' => esc_url_raw( home_url() ),
            )
        );

        wp_send_json($response);
    }

    public function orderpickingapp_product_metabox_callback($post) {
        ?>
        <br/>
        <div id="stock_mutations"></div>
        <button id="load_stock_mutations" data-product_id="<?php echo absint( $post->ID ); ?>" class="btn btn-primary">Load stock mutations</button>
        <button id="export_stock_mutations" data-product_id="<?php echo absint( $post->ID ); ?>" class="btn btn-primary">Export stock mutations</button>
        <?php
    }

    public function orderpickingapp_get_stock_mutations() {
        check_ajax_referer( 'orderpickingapp_nonce', 'security' );

        $product_id = isset( $_POST['product_id'] ) ? absint( wp_unslash( $_POST['product_id'] ) ) : 0;
        $product_ids = array( $product_id );

        $orderpickingapp_apikey = get_option('orderpickingapp_apikey');
        if (isset($orderpickingapp_apikey) && !empty($orderpickingapp_apikey)) {


            $product = wc_get_product( $product_id );

            if ($product && $product->is_type('variable')) {
                $variations = $product->get_children();
                $product_ids = array_merge($product_ids,$variations);
            }

            $url = add_query_arg(
                array(
                    'product_ids' => implode( ',', array_map( 'absint', $product_ids ) ),
                ),
                'https://orderpickingapp.com/wp-json/picking/v1/inventory-archive'
            );

            $response = $this->orderpickingapp_remote_get_json(
                $url,
                array(
                    'Authorization' => 'Bearer ' . $orderpickingapp_apikey,
                    'Referer' => esc_url_raw( home_url() ),
                )
            );

            $reasons = [
                'error_correction' => 'Correction of Errors',
                'loss_damage' => 'Loss or Damage',
                'returns' => 'Returns',
                'production_assembly' => 'Production and Assembly',
                'promotions_giveaways' => 'Promotions or Giveaways',
                'logistical_errors' => 'Logistical Errors',
                'inventory_management' => 'Inventory Management',
                'checker' => 'Inventory check',
                'manual_correction'	=> 'Manual Correction',
                'inventory_correction' => 'Correction after inventory',
                'add_stock' => 'Added stock',
                'checked' => 'Checked',
            ];

            ob_start();
            ob_clean();

            if( isset($response['message']) ){
                echo '<p style="color:red;">' . esc_html( $response['message'] ) . '!</p>';
            }
            else{
                echo "<table border='1' cellspacing='0' cellpadding='5'>";
                echo "<tr><th>Product ID</th><th>Name</th><th>User</th><th>Old Stock</th><th>Change</th><th>New Stock</th><th>Reason</th><th>Date</th></tr>";

                $previous_product_id = null;
                $background = "#eee;";
                foreach ($response as $product_id => $entries) {

                    // Haal de productnaam op
                    $product = wc_get_product($product_id);
                    $product_name = ($product && $product->get_name()) ? $product->get_name() : "Onbekend product";

                    $background = ($background === "#eee;") ? "#fff;" : "#eee;";

                    $entries = array_reverse($entries);

                    $i = 0;
                    foreach ($entries as $entry) {
                        if( $entry['Delta'] < 0 ){
                            $new_stock = abs($entry['Stock']) - abs($entry['Delta']);
                        }
                        else{
                            $new_stock = abs($entry['Stock']) + abs($entry['Delta']);
                        }

                        echo '<tr style="background-color:' . esc_attr( $background ) . '">';

                        if( $i == 0 ) {
                            echo '<td><strong>' . esc_html( $entry['ProductID'] ) . '</strong></td>';
                            echo '<td><strong>' . esc_html( $product_name ) . '</strong></td>';
                            echo '<td><strong>' . esc_html( $entry['User'] ) . '</strong></td>';
                            echo '<td><strong>' . esc_html( $entry['Stock'] ) . '</strong></td>';
                            echo '<td><strong>' . esc_html( $entry['Delta'] ) . '</strong></td>';
                            echo '<td><strong>' . esc_html( $new_stock ) . '</strong></td>';
                            echo '<td><strong>' . esc_html( $reasons[ $entry['Reason'] ] ?? $entry['Reason'] ) . '</strong></td>';
                            echo '<td><strong>' . esc_html( $entry['Created'] ) . '</strong></td>';
                        }
                        else{
                            echo '<td>' . esc_html( $entry['ProductID'] ) . '</td>';
                            echo '<td>' . esc_html( $product_name ) . '</td>';
                            echo '<td>' . esc_html( $entry['User'] ) . '</td>';
                            echo '<td>' . esc_html( $entry['Stock'] ) . '</td>';
                            echo '<td>' . esc_html( $entry['Delta'] ) . '</td>';
                            echo '<td>' . esc_html( $new_stock ) . '</td>';
                            echo '<td>' . esc_html( $reasons[ $entry['Reason'] ] ?? $entry['Reason'] ) . '</td>';
                            echo '<td>' . esc_html( $entry['Created'] ) . '</td>';
                        }

                        echo "</tr>";

                        $i++;
                    }
                }
                echo "</table>";
                echo "<br/>";
            }

            $html_output = ob_get_clean();

            wp_send_json_success($html_output);
            exit;
        }
    }

    public function orderpickingapp_export_stock_mutations() {
        check_ajax_referer( 'orderpickingapp_nonce', 'security' );

        $product_id  = isset( $_GET['product_id'] ) ? absint( wp_unslash( $_GET['product_id'] ) ) : 0;
        $product_ids = array( $product_id );
        $orderpickingapp_apikey = get_option('orderpickingapp_apikey');

        if (!isset($orderpickingapp_apikey) || empty($orderpickingapp_apikey)) {
            wp_send_json_error("API key ontbreekt.");
            exit;
        }

        $product = wc_get_product( $product_id );

        if ($product && $product->is_type('variable')) {
            $variations = $product->get_children();
            $product_ids = array_merge($product_ids, $variations);
        }

        $url = add_query_arg(
            array(
                'product_ids' => implode( ',', array_map( 'absint', $product_ids ) ),
            ),
            'https://orderpickingapp.com/wp-json/picking/v1/inventory-archive'
        );

        // Haal data op via API.
        $response = $this->orderpickingapp_remote_get_json(
            $url,
            array(
                'Authorization' => 'Bearer ' . $orderpickingapp_apikey,
                'Referer' => esc_url_raw( home_url() ),
            )
        );

        if (isset($response['message'])) {
            wp_send_json_error($response['message']);
            exit;
        }

        $reasons = [
            'error_correction' => 'Correction of Errors',
            'loss_damage' => 'Loss or Damage',
            'returns' => 'Returns',
            'production_assembly' => 'Production and Assembly',
            'promotions_giveaways' => 'Promotions or Giveaways',
            'logistical_errors' => 'Logistical Errors',
            'inventory_management' => 'Inventory Management',
            'checker' => 'Inventory check',
            'manual_correction' => 'Manual Correction',
            'inventory_correction' => 'Correction after inventory',
            'add_stock' => 'Added stock',
            'checked' => 'Checked',
        ];

        header('Content-Type: text/csv; charset=utf-8');
        header( 'Content-Disposition: attachment; filename=' . sanitize_file_name( $product_id . '_stock_mutations.csv' ) );

        $output = fopen('php://output', 'w');
        fputcsv($output, ['Product ID', 'Name', 'User', 'Old Stock', 'Change', 'New Stock', 'Reason', 'Date']);

        foreach ($response as $product_id => $entries) {
            $product = wc_get_product($product_id);
            $product_name = ($product && $product->get_name()) ? $product->get_name() : "Onbekend product";
            $entries = array_reverse($entries);

            foreach ($entries as $entry) {
                $new_stock = ($entry['Delta'] < 0)
                    ? abs($entry['Stock']) - abs($entry['Delta'])
                    : abs($entry['Stock']) + abs($entry['Delta']);
                $reason = $reasons[$entry['Reason']] ?? 'Unknown';
                fputcsv($output, [
                    $entry['ProductID'],
                    $product_name,
                    $entry['User'],
                    $entry['Stock'],
                    $entry['Delta'],
                    $new_stock,
                    $reason,
                    $entry['Created']
                ]);
            }
        }

        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- Closing direct CSV output stream.
        fclose( $output );
        exit;
    }

    function orderpickingapp_add_supplier_sku_field_to_variations($loop, $variation_data, $variation) {
        woocommerce_wp_text_input(array(
            'id'            => "variation_orderpickingapp_cost_price_{$loop}", // Uniek veld-ID
            'name'          => "variation_orderpickingapp_cost_price[{$variation->ID}]", // Naam van het veld
            'value'         => get_post_meta($variation->ID, 'orderpickingapp_cost_price', true), // Waarde ophalen
            'label' => __('Cost Price', 'order-picking-app'), // Label
            'placeholder' => __('Enter the cost price here', 'order-picking-app'),
            'desc_tip' => 'true',
            'description' => __('This is the cost price of the product. Provided by Order Picking App', 'order-picking-app'),
            'type' => 'number',
            'custom_attributes' => array(
                'step' => 'any',
                'min' => '0'
            ),
        ));
        woocommerce_wp_text_input(array(
            'id'            => "variation_orderpickingapp_supplier_sku_{$loop}", // Uniek veld-ID
            'name'          => "variation_orderpickingapp_supplier_sku[{$variation->ID}]", // Naam van het veld
            'value'         => get_post_meta($variation->ID, 'orderpickingapp_supplier_sku', true), // Waarde ophalen
            'label'         => __('Supplier SKU', 'order-picking-app'),
            'placeholder'   => __('Enter the supplier sku', 'order-picking-app'),
            'type'          => 'text',
        ));

        echo '<p class="form-row full-width">';
        echo '<strong>' . esc_html__( 'Last inventory check:', 'order-picking-app' ) . '</strong> ' . esc_html( get_post_meta( $variation->ID, 'last_inventory_date', true ) );
        echo '</p>';
    }

    function orderpickingapp_add_supplier_sku_field_for_variations($variation_id, $i) {
        if (
            ! isset( $_POST['woocommerce_meta_nonce'] ) ||
            ! wp_verify_nonce(
                sanitize_text_field( wp_unslash( $_POST['woocommerce_meta_nonce'] ) ),
                'woocommerce_save_data'
            )
        ) {
            return;
        }

        if (isset($_POST['variation_orderpickingapp_supplier_sku'][$variation_id])) {
            $supplier_sku = sanitize_text_field( wp_unslash( $_POST['variation_orderpickingapp_supplier_sku'][ $variation_id ] ) );
            update_post_meta($variation_id, 'orderpickingapp_supplier_sku', $supplier_sku);
        }
        if (isset($_POST['variation_orderpickingapp_cost_price'][$variation_id])) {
            $cost_price = sanitize_text_field( wp_unslash( $_POST['variation_orderpickingapp_cost_price'][ $variation_id ] ) );
            update_post_meta($variation_id, 'orderpickingapp_cost_price', $cost_price);
        }
    }

    function orderpickingapp_enqueue_supplier_sku_script() {
        if (is_product()) {
            ?>
            <script>
                jQuery(document).ready(function($) {
                    $('form.variations_form').on('show_variation', function(event, variation) {
                        if (variation.orderpickingapp_supplier_sku) {
                            $('.woocommerce-variation-price').after('<p class="orderpickingapp_supplier_sku">Supplier SKU: ' + variation.orderpickingapp_supplier_sku + '</p>');
                        }
                        if (variation.orderpickingapp_cost_price) {
                            $('.woocommerce-variation-price').after('<p class="orderpickingapp_cost_price">Cost price: ' + variation.orderpickingapp_cost_price + '</p>');
                        }
                    });
                    $('form.variations_form').on('hide_variation', function() {
                        $('.orderpickingapp_supplier_sku').remove();
                        $('.orderpickingapp_cost_price').remove();
                    });
                });
            </script>
            <?php
        }
    }


    function orderpickingapp_add_costs_price_field_to_general_tab() {
        global $post;

        $product_type = get_post_meta($post->ID, '_product_type', true);
        if ($product_type === 'simple') {
            woocommerce_wp_text_input(array(
                'id' => 'orderpickingapp_cost_price', // Meta key
                'label' => __('Cost Price', 'order-picking-app'), // Label
                'placeholder' => __('Enter the cost price here', 'order-picking-app'),
                'desc_tip' => 'true',
                'description' => __('This is the cost price of the product. Provided by Order Picking App', 'order-picking-app'),
                'type' => 'number',
                'custom_attributes' => array(
                    'step' => 'any',
                    'min' => '0'
                ),
            ));
        }
    }

    function orderpickingapp_add_supplier_sku_field_to_inventory_tab() {

        global $post;

        $product_type = get_post_meta($post->ID, '_product_type', true);
        if ($product_type === 'simple') {
            woocommerce_wp_text_input(array(
                'id' => 'orderpickingapp_supplier_sku', // Meta key
                'label' => __('Supplier SKU', 'order-picking-app'), // Label
                'placeholder' => __('Enter the supplier sku here', 'order-picking-app'),
                'desc_tip' => 'true',
                'description' => __('This is the supplier sku of the product. Provided by Order Picking App', 'order-picking-app'),
                'type' => 'text',
            ));
        }
    }

    function save_orderpickingapp_product_fields($product) {
        $product_id = is_object( $product ) && method_exists( $product, 'get_id' )
            ? absint( $product->get_id() )
            : 0;

        if (
            ! isset( $_POST['woocommerce_meta_nonce'] ) ||
            ! wp_verify_nonce(
                sanitize_text_field( wp_unslash( $_POST['woocommerce_meta_nonce'] ) ),
                'woocommerce_save_data'
            )
        ) {
            return;
        }

        if ( ! current_user_can( 'edit_product', $product_id ) ) {
            return;
        }

        if (isset($_POST['orderpickingapp_cost_price'])) {
            $product->update_meta_data('orderpickingapp_cost_price', sanitize_text_field( wp_unslash( $_POST['orderpickingapp_cost_price'] ) ));
        }
        if (isset($_POST['orderpickingapp_supplier_sku'])) {
            $product->update_meta_data('orderpickingapp_supplier_sku', sanitize_text_field( wp_unslash( $_POST['orderpickingapp_supplier_sku'] ) ));
        }
    }

    public function orderpickingapp_register_bulk_action( $bulk_actions ) {

        $bulk_actions['orderpickingapp_order_label_pdf'] = __( 'Download order label PDF(s)', 'order-picking-app' );

        $app_users = get_transient('app_users');

        if (!isset($app_users) || !$app_users) {
            $orderpickingapp_apikey = get_option('orderpickingapp_apikey');
            if (isset($orderpickingapp_apikey) && !empty($orderpickingapp_apikey)) {
                $url      = 'https://orderpickingapp.com/wp-json/account/v1/settings';
                $response = $this->orderpickingapp_remote_get_json(
                    $url,
                    array(
                        'Authorization' => 'Bearer ' . $orderpickingapp_apikey,
                        'Referer' => esc_url_raw( home_url() ),
                    )
                );

                if (isset($response['settings']['app_users'])) {
                    set_transient('app_users', $response['settings']['app_users'], (86400 * 7));
                    $app_users = $response['settings']['app_users'];
                }
            }
        }

        foreach ( (array) $app_users as $app_user ) {
            $app_user_name = isset( $app_user['app_users_name'] ) ? sanitize_text_field( $app_user['app_users_name'] ) : '';
            $app_user_key  = sanitize_key( str_replace( ' ', '_', strtolower( $app_user_name ) ) );
            $bulk_actions[ 'assign_orders_to_' . $app_user_key ] = sprintf(
            /* translators: %s: App user name. */
                __( 'Assign order(s) to %s', 'order-picking-app' ),
                esc_html( $app_user_name )
            );
        }

        return $bulk_actions;
    }

    public function orderpickingapp_handle_bulk_actions_shop_order( $redirect_url, $action, $order_ids ) {
        $action = sanitize_key( $action );

        if ( empty( $order_ids ) ) {
            return $redirect_url;
        }

        if ( 'orderpickingapp_order_label_pdf' === $action ) {
            $order_ids = array_values( array_filter( array_map( 'absint', (array) $order_ids ) ) );
            $ids        = implode( ',', $order_ids );

            $url = wp_nonce_url(
                add_query_arg(
                    array(
                        'action'    => 'orderpickingapp_order_label_pdf',
                        'order_ids' => $ids,
                    ),
                    admin_url( 'admin-post.php' )
                ),
                'orderpickingapp_order_label_pdf_bulk_' . md5( $ids )
            );

            return html_entity_decode( $url );
        }

        if ( false === strpos( $action, 'assign_orders_to' ) ) {
            return $redirect_url;
        }

        $user_claimed = sanitize_key(
            str_replace( 'assign_orders_to_', '', $action )
        );

        foreach ( array_map( 'absint', (array) $order_ids ) as $order_id ) {
            $order = wc_get_order( $order_id );

            if ( ! $order ) {
                continue;
            }

            $current_value = $order->get_meta( 'user_claimed' );

            if ( $current_value !== $user_claimed ) {
                $order->update_meta_data( 'user_claimed', $user_claimed );
                $order->save();
            }
        }

        return $redirect_url;
    }

    public function orderpickingapp_plugin_add_settings_link( $links ) {

        $settings_link = sprintf(
            '<a href="%1$s">%2$s</a>',
            esc_url( admin_url( 'admin.php?page=orderpickingapp-panel' ) ),
            esc_html__( 'Settings', 'order-picking-app' )
        );

        array_unshift( $links, $settings_link );

        return $links;
    }

    public function orderpickingapp_order_meta_boxes()
    {
        $screen = class_exists( '\Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController' ) && wc_get_container()->get( CustomOrdersTableController::class )->custom_orders_table_usage_is_enabled()
            ? wc_get_page_screen_id( 'shop-order' )
            : 'shop_order';

        add_meta_box(
            'orderpickingapp-order-meta-box',
            'Order Picking App',
            array($this, 'orderpickingapp_order_meta_box_callback'),
            $screen,
            'side',
            'high'
        );

        add_meta_box(
            'orderpickingapp_product_metabox',
            'Order Picking App | Stock mutations',
            array($this, 'orderpickingapp_product_metabox_callback'),
            'product',
            'normal',
            'high'
        );
    }

    public function orderpickingapp_order_meta_box_callback($post)
    {
        // Get the WC_Order object
        $order = is_a( $post, 'WP_Post' ) ? wc_get_order( $post->ID ) : $post;

        $user_claimed = $order->get_meta('user_claimed');
        $app_users = get_transient('app_users');
        if (!isset($app_users) || !$app_users) {

            $orderpickingapp_apikey = get_option('orderpickingapp_apikey');
            if (isset($orderpickingapp_apikey) && !empty($orderpickingapp_apikey)) {
                $url      = 'https://orderpickingapp.com/wp-json/account/v1/settings';
                $response = $this->orderpickingapp_remote_get_json(
                    $url,
                    array(
                        'Authorization' => 'Bearer ' . $orderpickingapp_apikey,
                        'Referer' => esc_url_raw( home_url() ),
                    )
                );

                if (isset($response['settings']['app_users'])) {
                    set_transient('app_users', $response['settings']['app_users'], (86400 * 7));
                    $app_users = $response['settings']['app_users'];
                }
            }
        }


        ob_start(); ?>

        <?php wp_nonce_field( 'orderpickingapp_save_order', 'orderpickingapp_order_nonce' ); ?>
        <h5><?php echo esc_html__( 'Change or assign picker to order', 'order-picking-app' ); ?></h5>
        <div class="form-group">
            <select name="user_claimed">
                <option value="">Select picker</option>
                <?php foreach ( (array) $app_users as $app_user ):

                    // Check for new settings with user_name and picking_amount
                    if (is_array($app_user)) {
                        $app_user = $app_user['app_users_name'];
                    }

                    $app_user_key = strtolower($app_user);
                    $app_user_key = str_replace(' ', '_', $app_user_key);
                    ?>
                    <option value="<?php echo esc_attr( $app_user_key ); ?>" <?php selected( $user_claimed, $app_user_key ); ?>><?php echo esc_html( $app_user ); ?></option>
                <?php endforeach; ?>
            </select>
        </div>

        <br/>
        <button id="resetOrderPickingData" class="button button-secondary" data-order-id="<?php echo esc_attr( $order->get_id() ); ?>">Reset picking data</button>

        <script>
            jQuery(document).on('click', '#resetOrderPickingData', function(e){
                e.preventDefault();
                const orderId = jQuery(this).data('order-id');  // Haal order ID op uit de button

                if(confirm('Are you sure to delete all picking data for this order? After this action you have to re-pick the complete order!')) {
                    jQuery.ajax({
                        type: "POST",
                        url: '<?php echo esc_js( admin_url( 'admin-ajax.php' ) ); ?>',
                        data: {
                            'action': 'reset_order_picking_data',
                            'order_id': orderId,  // Verstuur de order ID
                            'security': '<?php echo esc_js( wp_create_nonce( "reset_orderpickingapp_nonce" ) ); ?>'  // Nonce voor beveiliging
                        },
                        dataType: 'JSON',
                        success: function(response){
                            if(response.success) {
                                alert('Picking data has been reset successfully.');
                                location.reload();
                            } else {
                                alert('Failed to reset data. Please try again.');
                            }
                        },
                        error: function(xhr, status, error) {
                            console.error('AJAX Error:', error);
                            alert('An error occurred. Please try again later.');
                        }
                    });
                }
            });
        </script>
        <?php
        $orderpickingapp_meta_box_html = ob_get_clean();
        echo $orderpickingapp_meta_box_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Buffered admin meta box output is escaped inline and contains required JavaScript.
    }

    public function save_orderpickingapp_order_meta_box_data($order_id)
    {
        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
            return;
        }

        if ( ! current_user_can( 'edit_shop_order', $order_id ) && ! current_user_can( 'manage_woocommerce' ) ) {
            return;
        }

        if (
            ! isset( $_POST['orderpickingapp_order_nonce'] ) ||
            ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['orderpickingapp_order_nonce'] ) ), 'orderpickingapp_save_order' )
        ) {
            return;
        }

        if (isset($_POST['user_claimed'])) {
            $user_claimed = sanitize_key( wp_unslash( $_POST['user_claimed'] ) );
            $order = wc_get_order( $order_id );
            if ( ! $order ) {
                return;
            }
            $current_value = $order->get_meta('user_claimed');
            if ($current_value !== $user_claimed) {
                $order->update_meta_data('user_claimed', $user_claimed);
                $order->save();

                $orderpickingapp_apikey = get_option('orderpickingapp_apikey');
                if (!isset($orderpickingapp_apikey) || empty($orderpickingapp_apikey)){

                    $data = array(
                        'platform' => 'order-picking-app',
                        'type'     => 'picker_assigned',
                        'message'  => sprintf(
                        /* translators: %s: Name of the assigned picker. */
                            __( 'New order assigned to picker: %s', 'order-picking-app' ),
                            sanitize_text_field( $user_claimed )
                        ),
                    );

                    $url      = 'https://orderpickingapp.com/wp-json/picking/v1/send-push-message';
                    $response = wp_remote_post(
                        esc_url_raw( $url ),
                        array(
                            'timeout'     => 30,
                            'redirection' => 5,
                            'headers'     => array(
                                'Authorization' => 'Bearer ' . ( isset( $_POST['token'] ) ? sanitize_text_field( wp_unslash( $_POST['token'] ) ) : '' ),
                                'Referer' => esc_url_raw( home_url() ),
                                'Content-Type'  => 'application/json',
                            ),
                            'body'        => wp_json_encode( $data ),
                        )
                    );
                }
            }
        }
    }

    public function add_orderpickingapp_taxonomies() {
        register_taxonomy(
            'orderpickingapp_supplier',
            'product',
            array(
                'hierarchical'      => false,
                'show_admin_column' => true,
                'show_in_nav_menus' => true,
                'labels'            => array(
                    'name'              => __( 'Suppliers', 'order-picking-app' ),
                    'singular_name'     => __( 'Supplier', 'order-picking-app' ),
                    'search_items'      => __( 'Search suppliers', 'order-picking-app' ),
                    'all_items'         => __( 'All suppliers', 'order-picking-app' ),
                    'parent_item'       => __( 'Parent supplier', 'order-picking-app' ),
                    'parent_item_colon' => __( 'Parent supplier:', 'order-picking-app' ),
                    'edit_item'         => __( 'Edit supplier', 'order-picking-app' ),
                    'update_item'       => __( 'Update supplier', 'order-picking-app' ),
                    'add_new_item'      => __( 'Add supplier', 'order-picking-app' ),
                    'new_item_name'     => __( 'Add suppliers', 'order-picking-app' ),
                    'menu_name'         => __( 'Suppliers', 'order-picking-app' ),
                ),
                'rewrite'          => array(
                    'slug'         => 'suppliers',
                    'with_front'   => false,
                    'hierarchical' => false,
                ),
            )
        );
    }

    public function orderpickingapp_missing_app_token_message() {
        $orderpickingapp_apikey = get_option( 'orderpickingapp_apikey' );

        if ( empty( $orderpickingapp_apikey ) ) {
            $this->orderpickingapp_create_message(
                'error',
                sprintf(
                /* translators: %s: URL to the free trial page. */
                    __(
                        'Not activated, create a 30-day free trial to work faster and more accurately. <a class="btn button" style="margin-left: 10px;" href="%s">Start free trial</a>',
                        'order-picking-app'
                    ),
                    esc_url( admin_url( 'admin.php?page=orderpickingapp-panel' ) )
                )
            );
        }
    }

    private function orderpickingapp_create_message($status, $message)
    {
        // Check whether the values are entered
        if (isset($status) && !empty($status) && $status != '' && $status != null && isset($message) && !empty($message) && $message != '' && $message != null) {
            $status = strtolower($status);
            if ($status != "error" && $status != "success" && $status != "warning" && $status != "info") {
                $status = "info";
            }

            $class = 'notice notice-' . $status;
            printf( '<div class="%1$s"><p>Order Picking App | %2$s</p></div>', esc_attr( $class ), wp_kses_post( $message ) );
        }
    }

    public function orderpickingapp_enqueue_plugin_styles_scripts()
    {
        if (is_admin()) {
            ?>
            <script type="text/javascript">
                var ajaxurl = '<?php echo esc_js( admin_url( 'admin-ajax.php' ) ); ?>';
            </script>
            <?php
        }
    }

    /**
     * Genereer een A6 orderlabel als PDF.
     */
    public function orderpickingapp_order_label_pdf() {
        if ( ! current_user_can( 'manage_woocommerce' ) ) {
            wp_die( esc_html__( 'Onvoldoende rechten.', 'order-picking-app' ), '', array( 'response' => 403 ) );
        }

        $order_ids = array();

        if ( isset( $_GET['order_id'] ) ) {
            $order_ids[] = absint( wp_unslash( $_GET['order_id'] ) );
        } elseif ( isset( $_GET['order_ids'] ) ) {
            $order_ids = array_map(
                'absint',
                explode( ',', sanitize_text_field( wp_unslash( $_GET['order_ids'] ) ) )
            );
        }

        $order_ids = array_values( array_filter( array_unique( $order_ids ) ) );
        $ids       = implode( ',', $order_ids );
        $nonce     = isset( $_GET['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ) : '';

        if ( empty( $order_ids ) ) {
            wp_die(
                esc_html__( 'Ongeldige aanvraag.', 'order-picking-app' ),
                '',
                array( 'response' => 400 )
            );
        }

        $is_bulk_request = isset( $_GET['order_ids'] );
        $nonce_is_valid = $is_bulk_request
            ? wp_verify_nonce( $nonce, 'orderpickingapp_order_label_pdf_bulk_' . md5( $ids ) )
            : wp_verify_nonce( $nonce, 'orderpickingapp_order_label_pdf_' . $order_ids[0] );

        if ( empty( $order_ids ) || ! $nonce_is_valid ) {
            wp_die( esc_html__( 'Ongeldige aanvraag.', 'order-picking-app' ), '', array( 'response' => 400 ) );
        }

        if ( ! class_exists( '\\Dompdf\\Dompdf' ) || ! class_exists( '\\Picqer\\Barcode\\BarcodeGeneratorHTML' ) ) {
            require_once plugin_dir_path( dirname( __FILE__ ) ) . 'vendor/autoload.php';
        }

        if ( ! class_exists( '\\Dompdf\\Dompdf' ) || ! class_exists( '\\Picqer\\Barcode\\BarcodeGeneratorHTML' ) ) {
            wp_die( esc_html__( 'De PDF- of barcodebibliotheek ontbreekt.', 'order-picking-app' ), '', array( 'response' => 500 ) );
        }

        $barcode_generator = new \Picqer\Barcode\BarcodeGeneratorHTML();
        $labels            = array();
        $label_orders      = array();

        $logo_url  = 'https://orderpickingapp.com/wp-content/uploads/2022/11/OPA-logo-e1670274210119.png';
        $logo_data = '';

        $logo_response = wp_remote_get(
            $logo_url,
            array(
                'timeout' => 10,
            )
        );

        if ( ! is_wp_error( $logo_response ) && 200 === wp_remote_retrieve_response_code( $logo_response ) ) {
            $logo_body         = wp_remote_retrieve_body( $logo_response );
            $logo_content_type = wp_remote_retrieve_header( $logo_response, 'content-type' );

            if ( $logo_body && $logo_content_type ) {
                $logo_data = 'data:' . $logo_content_type . ';base64,' . base64_encode( $logo_body );
            }
        }

        foreach ( $order_ids as $order_id ) {
            $order = wc_get_order( $order_id );

            if ( ! $order ) {
                continue;
            }

            $order_number = (string) $order->get_order_number();
            $created      = $order->get_date_created();
            $order_date   = $created ? wc_format_datetime( $created, wc_date_format() . ' ' . wc_time_format() ) : '';

            $customer     = trim( $order->get_formatted_billing_full_name() );
            if ( '' === $customer ) {
                $customer = trim( $order->get_formatted_shipping_full_name() );
            }
            if ( '' === $customer ) {
                $customer = esc_html__( 'Onbekende klant', 'order-picking-app' );
            }

            $postcode = trim( (string) $order->get_shipping_postcode() );
            if ( '' === $postcode ) {
                $postcode = trim( (string) $order->get_billing_postcode() );
            }
            if ( '' === $postcode ) {
                $postcode = '-';
            }

            $product_count = 0;
            foreach ( $order->get_items( 'line_item' ) as $item ) {
                $product_count += max( 0, (int) $item->get_quantity() );
            }

            $barcode_html = $barcode_generator->getBarcode(
                $order_number,
                \Picqer\Barcode\BarcodeGeneratorHTML::TYPE_CODE_128,
                2,
                70
            );

            $logo_html = '';

            if ( '' !== $logo_data ) {
                $logo_html = '<img class="logo" src="' . esc_attr( $logo_data ) . '" alt="Order Picking App">';
            }

            $labels[] = '<div class="label">'
                . '<div class="header">'
                . '<div class="logo-wrapper">' . $logo_html . '</div>'
                . '<div class="title">' . esc_html__( 'Orderpick Label', 'order-picking-app' ) . '</div>'
                . '<div class="header-spacer"></div>'
                . '</div>'
                . '<table class="details">'
                . '<tr><th>' . esc_html__( 'Date', 'order-picking-app' ) . '</th><td>' . esc_html( $order_date ) . '</td></tr>'
                . '<tr><th>' . esc_html__( 'Name', 'order-picking-app' ) . '</th><td>' . esc_html( $customer ) . '</td></tr>'
                . '<tr><th>' . esc_html__( 'Postcode', 'order-picking-app' ) . '</th><td>' . esc_html( $postcode ) . '</td></tr>'
                . '<tr><th>' . esc_html__( 'Products', 'order-picking-app' ) . '</th><td>' . esc_html( (string) $product_count ) . '</td></tr>'
                . '<tr><th>' . esc_html__( 'Total', 'order-picking-app' ) . '</th><td>' . esc_html( (string) $order->get_total() ) . '</td></tr>'
                . '<tr><th>' . esc_html__( 'Shipping', 'order-picking-app' ) . '</th><td>' . esc_html( (string) $order->get_shipping_method() ) . '</td></tr>'
                . '</table>'
                . '<div class="barcode">' . $barcode_html . '</div>'
                . '<div class="number">' . esc_html( $order_number ) . '</div>'
                . '</div>';

            $label_orders[] = $order;
        }

        if ( empty( $labels ) ) {
            wp_die( esc_html__( 'Geen geldige bestellingen gevonden.', 'order-picking-app' ), '', array( 'response' => 404 ) );
        }

        $html = '<!doctype html><html><head><meta charset="utf-8"><style>
            @page {
                margin: 4mm;
            }
        
            * {
                box-sizing: border-box;
            }
        
            body {
                margin: 0;
                color: #111;
                font-family: DejaVu Sans, sans-serif;
            }
        
            .label {
                width: 100%;
                text-align: center;
                page-break-after: always;
            }
        
            .label:last-child {
                page-break-after: auto;
            }
        
            .header {
                display: table;
                width: 100%;
                margin-bottom: 2mm;
            }
        
            .logo-wrapper,
            .title,
            .header-spacer {
                display: table-cell;
                width: 33.33%;
                vertical-align: middle;
            }
        
            .logo-wrapper {
                text-align: left;
            }
        
            .logo {
                display: block;
                max-width: 35mm;
                max-height: 14mm;
            }
        
            .title {
                margin: 0;
                font-size: 16pt;
                font-weight: 700;
                text-align: center;
                white-space: nowrap;
            }
        
            .header-spacer {
                text-align: right;
            }
        
            .details {
                width: 100%;
                margin: 0 0 4mm;
                border-collapse: collapse;
                font-size: 10pt;
                text-align: left;
            }
        
            .details th {
                width: 35%;
                padding: 0.8mm 1mm;
                vertical-align: top;
            }
        
            .details td {
                padding: 0.8mm 1mm;
                vertical-align: top;
            }
        
            .barcode {
                display: inline-block;
                margin: 1mm auto 2mm;
            }
        
            .number {
                font-size: 16pt;
                font-weight: 700;
                letter-spacing: 1px;
            }
        </style></head><body>' . implode( '', $labels ) . '</body></html>';

        $options = new \Dompdf\Options();
        $options->set( 'isRemoteEnabled', false );
        $options->set( 'isHtml5ParserEnabled', true );

        $dompdf = new \Dompdf\Dompdf( $options );
        $dompdf->loadHtml( $html, 'UTF-8' );
        $dompdf->setPaper( 'A6', 'landscape' );
        $dompdf->render();

        // Markeer de orders pas nadat de PDF succesvol is opgebouwd.
        foreach ( $label_orders as $label_order ) {
            $label_order->update_meta_data( '_orderpickingapp_order_label_created_at', time() );
            $label_order->save();
        }

        // Voorkom dat notices, whitespace of eerdere output de PDF-download beschadigen.
        while ( ob_get_level() > 0 ) {
            ob_end_clean();
        }

        $dompdf->stream(
            sanitize_file_name( 1 === count( $labels ) ? 'order-label.pdf' : 'order-labels.pdf' ),
            array( 'Attachment' => true )
        );
        exit;
    }

    public function add_orderpickingapp_order_column($columns)
    {
        $columns['order-picking-app'] = 'Order Picking';
        return $columns;
    }

    public function add_orderpickingapp_order_column_value( $column, $post_id ) {

        if ( 'order-picking-app' !== $column ) {
            return;
        }

        $order = wc_get_order( $post_id );

        if ( ! $order ) {
            return;
        }

        $user_claimed = $order->get_meta( 'user_claimed' );
        $user_claimed = str_replace( '_', ' ', $user_claimed );

        if ( empty( $user_claimed ) ) {
            $user_claimed = esc_html__( 'Unassigned', 'order-picking-app' );
        }

        $packer = $order->get_meta( 'packer' );
        $packer = str_replace( '_', ' ', $packer );

        if ( empty( $packer ) ) {
            $packer = esc_html__( 'Unassigned', 'order-picking-app' );
        }

        $picking_status = $order->get_meta( 'picking_status' );

        if ( ! empty( $picking_status ) ) {

            echo esc_html__(
                    'Status:',
                    'order-picking-app'
                ) . ' ' . esc_html( ucfirst( $picking_status ) );

            echo '<br>';

        } else {

            echo esc_html__(
                'Status: Open',
                'order-picking-app'
            );

            echo '<br>';
        }

        echo esc_html__(
                'Picker:',
                'order-picking-app'
            ) . ' ' . esc_html( ucfirst( $user_claimed ) );

        $batch_id = $order->get_meta( 'batch_id' );

        if ( ! empty( $batch_id ) ) {

            echo '<br>';

            echo esc_html__(
                    'Batch:',
                    'order-picking-app'
                ) . ' ' . esc_html( $batch_id );
        }

        if ( 'completed' === $picking_status ) {

            echo '<br>';

            echo esc_html__(
                    'Packer:',
                    'order-picking-app'
                ) . ' ' . esc_html( ucfirst( $packer ) );
        }

        $ordernote = $order->get_meta( 'ordernote' );

        if ( ! empty( $ordernote ) ) {

            echo '<br>';

            echo esc_html__(
                    'Note:',
                    'order-picking-app'
                ) . ' ' . esc_html( $ordernote );
        }

        echo '<br>';

        printf(
        /* translators: %d: Number of items in the order. */
            esc_html__(
                'Items: %d',
                'order-picking-app'
            ),
            absint( count( $order->get_items() ) )
        );

        $label_url = wp_nonce_url(
            add_query_arg(
                array(
                    'action'   => 'orderpickingapp_order_label_pdf',
                    'order_id' => $order->get_id(),
                ),
                admin_url( 'admin-post.php' )
            ),
            'orderpickingapp_order_label_pdf_' . $order->get_id()
        );

        $label_created_at = absint( $order->get_meta( '_orderpickingapp_order_label_created_at' ) );
        $label_is_created = 0 < $label_created_at;
        $label_button_text = $label_is_created
            ? __( 'Label PDF ✓', 'order-picking-app' )
            : __( 'Label PDF', 'order-picking-app' );
        $label_button_style = 'margin-top:6px;';
        $label_button_title = '';

        if ( $label_is_created ) {
            $label_button_style .= 'background:#00a32a;border-color:#008a20;color:#fff;box-shadow:none;';
            $label_button_title = sprintf(
            /* translators: %s: Date and time when the order label was generated. */
                __( 'Label aangemaakt op %s', 'order-picking-app' ),
                wp_date(
                    get_option( 'date_format' ) . ' ' . get_option( 'time_format' ),
                    $label_created_at
                )
            );
        }

        $label_button_onclick = "this.style.background='#00a32a';this.style.borderColor='#008a20';this.style.color='#fff';this.style.boxShadow='none';this.textContent='" . esc_js( __( 'Label PDF ✓', 'order-picking-app' ) ) . "';";

        echo '<br><a class="button button-small" style="' . esc_attr( $label_button_style ) . '" href="' . esc_url( $label_url ) . '" target="_blank" rel="noopener" title="' . esc_attr( $label_button_title ) . '" onclick="' . esc_attr( $label_button_onclick ) . '">'
            . esc_html( $label_button_text )
            . '</a>';
    }

    public function add_orderpickingapp_admin_pages()
    {
        add_menu_page('Order Picking App', 'Order Picking App', 'manage_options', 'orderpickingapp-panel', array($this, 'orderpickingapp_settings_page'), plugin_dir_url(__FILE__) . 'images/dashicon.png', 99);
    }

    public function display_orderpickingapp_panel_fields() {
        add_settings_section(
            'orderpickingapp_section',
            '',
            null,
            'orderpickingapp_options'
        );

        add_settings_field(
            'orderpickingapp_apikey',
            'API key',
            array( $this, 'orderpickingapp_display_apiKey_element' ),
            'orderpickingapp_options',
            'orderpickingapp_section'
        );

        register_setting(
            'orderpickingapp_options',
            'orderpickingapp_apikey',
            array(
                'sanitize_callback' => 'sanitize_text_field',
            )
        );
    }

    public function orderpickingapp_display_apiKey_element()
    {
        $orderpickingapp_apikey = get_option('orderpickingapp_apikey');
        ?>
        <input type='text' name='orderpickingapp_apikey' id='orderpickingapp_apikey'
               value='<?php echo esc_attr( $orderpickingapp_apikey ); ?>' style='width: 100%; min-wdith: 250px;'/>
        <hr>
        <?php
    }

    public function orderpickingapp_save_app_settings()
    {
        check_ajax_referer( 'orderpickingapp_nonce', 'security' );

        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error(
                array(
                    'message' => __( 'Unauthorized.', 'order-picking-app' ),
                ),
                403
            );
        }

        $data_array = array();
        $app_users_counter = 0;
        $app_users = array();

        $order_status_found = false;
        $packing_status_found = false;

        $posted_data = array();
        if ( isset( $_POST['data'] ) && is_array( $_POST['data'] ) ) {
            $posted_data = map_deep(
                wp_unslash( $_POST['data'] ),
                'sanitize_text_field'
            );
        }

        $allowed_options = array(

            // API / account
            'orderpickingapp_apikey',
            'orderpickingapp_subscription_id',

            // Branding
            'logoUrl',
            'allow_logo_use',

            // Picking
            'picking_amount',
            'pick_by',
            'pickroute',
            'pickingDate',

            // Scanner
            'use_barcodescanner',

            // Order statussen
            'orderpickingapp_order_status',
            'picking_order_status',
            'packing_order_status',
            'completed_order_status',
            'packing_order_status_mapping',

            // Pickup / delivery
            'enable_pickup_list',
            'pickup_list_method',
            'enable_delivery_list',
            'delivery_list_method',

            // Order afhandeling
            'manual_order_assigning',
            'skip_packing',
            'disable_backorders',
            'disable_product_combining',
            'auto_completed_order',

            // Product/meta velden
            'orderpickingapp_location_field',
            'orderpickingapp_ean_field',
            'orderpickingapp_additional_barcode_field',
            'orderpickingapp_additional_box_amount_field',

            // Layout
            'hide_order_total',
            'hide_product_description',
            'hide_product_location',
            'show_product_description',
            'show_custom_order_field_in_list',
            'show_pdf_images',

            // App functies
            'enable_batch_order_select',
            'disable_inventory_update',
            'disable_picking_list_view',
            'enable_fast_picking',
            'enable_fast_packing',
            'enable_packing_product_check',
            'pre_picking_summary',
            'limit_stock_mutation',
            'show_picking_timer',
            'enable_order_push_notifications',

            // Shops
            'connected_shops',

            // Public display access (stored centrally in the portal)
            'narrowcasting_access_token',
            'packing_access_token',
            'packing_allowed_ips',
            'packing_link_enabled',

            // Prefix
            'order_prefix',

            // Users
            'app_users',
        );

        foreach ( $posted_data as $item ) {

            if ($item['name'] === 'pickroute' && !empty($item['value'])) {
                $values = is_array($item['value']) ? $item['value'] : [$item['value']];

                foreach ($values as $value) {
                    $value = sanitize_text_field($value);

                    if (!in_array($value, $data_array['pickroute'] ?? [], true)) {
                        $data_array['pickroute'][] = $value;
                    }
                }
            }
            elseif (str_contains($item['name'], 'app_users')) {
                if (isset($item['value'])) {
                    if (str_contains($item['name'], 'app_users_name')) {
                        $app_users[$app_users_counter]['app_users_name'] = sanitize_text_field( $item['value'] );
                    } elseif (str_contains($item['name'], 'app_users_password')) {
                        $app_users[$app_users_counter]['app_users_password'] = sanitize_text_field( $item['value'] );
                    } elseif (str_contains($item['name'], 'app_users_start_time')) {
                        $app_users[$app_users_counter]['app_users_start_time'] = sanitize_text_field( $item['value'] );
                    } elseif (str_contains($item['name'], 'app_users_end_time')) {
                        $app_users[$app_users_counter]['app_users_end_time'] = sanitize_text_field( $item['value'] );
                    } elseif (str_contains($item['name'], 'app_users_picking_amount')) {
                        $app_users[$app_users_counter]['app_users_picking_amount'] = sanitize_text_field( $item['value'] );
                    } elseif (str_contains($item['name'], 'app_users_type')) {
                        $app_users[$app_users_counter]['app_users_type'] = sanitize_key( $item['value'] );
                    } elseif (str_contains($item['name'], 'app_users_force_scan_all')) {
                        $app_users[$app_users_counter]['app_users_force_scan_all'] = !empty($item['value']) ? 1 : 0;
                        $app_users_counter++;
                    }
                }
            } elseif (str_contains($item['name'], 'orderpickingapp_order_status')) {
                $order_status_found = true;

                if (!isset($data_array['orderpickingapp_order_status'])) {
                    $data_array['orderpickingapp_order_status'] = array();
                }

                if (isset($item['value']) && $item['value'] !== '') {
                    $data_array['orderpickingapp_order_status'][ sanitize_key( $item['value'] ) ] = sanitize_key( $item['value'] );
                }
            }
            elseif (str_contains($item['name'], 'orderpickingapp_packing_status')) {
                $packing_status_found = true;

                if (!isset($data_array['packing_order_status_mapping'])) {
                    $data_array['packing_order_status_mapping'] = array();
                }

                if (isset($item['value']) && $item['value'] !== '') {
                    $key = str_replace(array('orderpickingapp_packing_status[', ']'), '', $item['name']);
                    $data_array['packing_order_status_mapping'][ sanitize_key( $key ) ] = sanitize_key( $item['value'] );
                }
            }
            elseif (str_contains($item['name'], 'pickup_list_method')) {
                if (!isset($data_array['pickup_list_method_mapping'])) {
                    $data_array['pickup_list_method_mapping'] = array();
                }

                if (isset($item['value']) && $item['value'] !== '' && $item['value'] !== '0' && !is_array($item['value'])) {
                    $data_array['pickup_list_method_mapping'][sanitize_key( $item['value'])] = $item['value'];
                }
            }
            elseif (str_contains($item['name'], 'delivery_list_method')) {
                if (!isset($data_array['delivery_list_method_mapping'])) {
                    $data_array['delivery_list_method_mapping'] = array();
                }

                if (isset($item['value']) && $item['value'] !== '0' && $item['value'] !== '' && !is_array($item['value'])) {
                    $data_array['delivery_list_method_mapping'][sanitize_key( $item['value'])] = $item['value'];
                }
            }
            else {

                if (array_key_exists('value', $item)) {
                    $option_name = sanitize_key( $item['name'] );
                    $option_value = sanitize_text_field( $item['value'] );
                    $data_array[ $option_name ] = $option_value;
                    if ( ! in_array( $option_name, $allowed_options, true ) ) {
                        continue;
                    }

                    update_option( $option_name, $option_value );
                }
            }
        }

        if ($order_status_found) {
            $statuses = array_values($data_array['orderpickingapp_order_status'] ?? array());
            $data_array['orderpickingapp_order_status'] = $statuses;
            update_option('orderpickingapp_order_status', $statuses);
        }

        if ($packing_status_found) {
            update_option('packing_order_status_mapping', $data_array['packing_order_status_mapping'] ?? array());
            unset($data_array['packing_order_status_mapping']);
        }

        if (isset($data_array['pickup_list_method_mapping'])) {
            update_option('pickup_list_method', $data_array['pickup_list_method_mapping'] ?? array());
            unset($data_array['pickup_list_method_mapping']);
        }
        if (isset($data_array['delivery_list_method_mapping'])) {
            update_option('delivery_list_method', $data_array['delivery_list_method_mapping'] ?? array());
            unset($data_array['delivery_list_method_mapping']);
        }

        if (!empty($app_users)) {
            $data_array['app_users'] = $app_users;
            set_transient('app_users', $data_array['app_users'], (86400 * 7));
        }

        $token = isset( $_POST['token'] ) ? sanitize_text_field( wp_unslash( $_POST['token'] ) ) : '';

        $url      = 'https://orderpickingapp.com/wp-json/account/v1/settings';
        $response = wp_remote_post(
            esc_url_raw( $url ),
            array(
                'timeout'     => 120,
                'redirection' => 5,
                'headers'     => array(
                    'Authorization' => 'Bearer ' . $token,
                    'Referer' => esc_url_raw( home_url() ),
                    'Content-Type'  => 'application/json',
                ),
                'body'        => wp_json_encode( $data_array ),
            )
        );

        $response = is_wp_error( $response ) ? false : json_decode( wp_remote_retrieve_body( $response ), true );

        $args = array(
            'status'  => is_array( $response ) ? ( $response['status'] ?? 'error' ) : 'error',
            'message' => is_array( $response ) ? ( $response['message'] ?? 'Onbekende fout' ) : __( 'Remote request failed.', 'order-picking-app' ),
        );

        wp_send_json($args);
    }

    public function orderpickingapp_reset_api_key()
    {
        check_ajax_referer( 'orderpickingapp_nonce', 'security' );

        delete_option('orderpickingapp_apikey');
        wp_send_json_success( array( 'message' => esc_html__( 'API key reset.', 'order-picking-app' ) ) );
    }

    public function orderpickingapp_reset_picking_data_callback()
    {
        check_ajax_referer( 'reset_orderpickingapp_nonce', 'security' );

        if ( ! current_user_can( 'manage_woocommerce' ) ) {
            wp_send_json_error( array( 'message' => esc_html__( 'Unauthorized', 'order-picking-app' ) ), 403 );
        }

        $order_id = isset( $_POST['order_id'] ) ? absint( wp_unslash( $_POST['order_id'] ) ) : 0;  // Haal de order ID op

        if ($order_id === 0) {
            wp_send_json_error(['message' => 'Invalid order ID']);
        }

        $order = wc_get_order($order_id);
        if ($order) {
            $order->add_order_note('Order Picking App | Picking data reset done. Order have to be re-picked!');
            $order->delete_meta_data('batch_id');
            $order->delete_meta_data('claimed');
            $order->delete_meta_data('ordernote');
            $order->delete_meta_data('picking_status');
            $order->delete_meta_data('user_claimed');
            $order->save();
        }

        wp_send_json_success(['message' => 'Data reset successfully']);
    }

    public function  orderpickingapp_create_user_account()
    {
        check_ajax_referer( 'orderpickingapp_nonce', 'security' );

        $data_array = array();

        $posted_data = array();
        if ( isset( $_POST['data'] ) && is_array( $_POST['data'] ) ) {
            $posted_data = map_deep(
                wp_unslash( $_POST['data'] ),
                'sanitize_text_field'
            );
        }

        foreach ( $posted_data as $item ) {
            if (isset($item['value']) && !empty($item['value'])) {
                $data_array[ sanitize_key( $item['name'] ) ] = sanitize_text_field( $item['value'] );
            }
        }

        $url      = 'https://orderpickingapp.com/wp-json/account/v1/create-user';
        $response = wp_remote_post(
            esc_url_raw( $url ),
            array(
                'timeout'     => 30,
                'redirection' => 5,
                'headers'     => array(
                    'Content-Type' => 'application/json',
                    'Referer' => esc_url_raw( home_url() ),
                ),
                'body'        => wp_json_encode( $data_array ),
            )
        );

        $response = is_wp_error( $response ) ? false : json_decode( wp_remote_retrieve_body( $response ), true );

        if ( is_array( $response ) && isset( $response['token'] ) ) {
            update_option( 'orderpickingapp_apikey', sanitize_text_field( $response['token'] ) );

            $args = array(
                'status'  => $response['status'] ?? 'success',
                'message' => '',
            );
            wp_send_json( $args );
        } else {
            $args = array(
                'status'  => is_array( $response ) ? ( $response['status'] ?? 'error' ) : 'error',
                'message' => is_array( $response ) ? ( $response['message'] ?? __( 'Remote request failed.', 'order-picking-app' ) ) : __( 'Remote request failed.', 'order-picking-app' ),
            );
            wp_send_json( $args );
        }
    }

    public function orderpickingapp_settings_page()
    {
        require_once plugin_dir_path(__FILE__) . 'partials/orderpickingapp-settings-page.php';
    }

    public function  orderpickingapp_get_all_meta_keys( $post_type = 'post', $exclude_empty = false, $exclude_hidden = false ) {
        global $wpdb;

        $post_type = sanitize_key( $post_type );

        $cache_key = 'orderpickingapp_meta_keys_' . md5(
                wp_json_encode(
                    array(
                        'post_type'       => $post_type,
                        'exclude_empty'   => (bool) $exclude_empty,
                        'exclude_hidden'  => (bool) $exclude_hidden,
                    )
                )
            );

        $meta_keys = wp_cache_get( $cache_key, 'order-picking-app' );

        if ( false !== $meta_keys ) {
            return $meta_keys;
        }

        // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $wpdb table names are safe.
        $query = "
            SELECT DISTINCT pm.meta_key
            FROM {$wpdb->posts} p
            LEFT JOIN {$wpdb->postmeta} pm
                ON p.ID = pm.post_id
            WHERE p.post_type = %s
        ";

        if ( $exclude_empty ) {
            $query .= " AND pm.meta_key != ''";
        }

        if ( $exclude_hidden ) {
            $query .= " AND pm.meta_key NOT REGEXP '(^[_0-9].+$)'";
        }

        $meta_keys = $wpdb->get_col(
            $wpdb->prepare(
                $query, // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
                $post_type
            )
        );

        wp_cache_set( $cache_key, $meta_keys, 'order-picking-app', 300 );

        return $meta_keys;
    }

    public function  orderpickingapp_downloadCSVExport()
    {
        check_ajax_referer( 'orderpickingapp_nonce', 'security' );

        // output headers so that the file is downloaded rather than displayed
        header('Content-Type: text/csv; charset=utf-8');
        header('Content-Disposition: attachment; filename=picking_analytics.csv');

        // create a file pointer connected to the output stream
        $output = fopen('php://output', 'w');

        // output the column headings
        fputcsv($output, array('Picker', 'Total orders', 'Total products', 'Total items', 'Avg. time order (min)', 'Avg. time product (min)', 'Avg. time items (min)'));

        $url   = 'https://orderpickingapp.com/wp-json/picking/v1/analytics';
        $token = isset( $_POST['token'] ) ? sanitize_text_field( wp_unslash( $_POST['token'] ) ) : '';

        $response = $this->orderpickingapp_remote_get_json(
            $url,
            array(
                'Authorization' => 'Bearer ' . $token,
                'Referer' => esc_url_raw( home_url() ),
            )
        );
        if ($response['status'] == '200'){
            $AnalyticsData = $response['data'];

            foreach ($AnalyticsData['app_users'] as $picker) {
                if ($picker['app_users_type'] === 'sales' || $picker['app_users_type'] === 'inventory') {
                    continue;
                }

                $row_data = array(
                    (isset($picker['app_users_name'])) ? $picker['app_users_name'] : 'Default',
                    $picker['total_orders'],
                    (isset($picker['total_product_count'])) ? $picker['total_product_count'] : '0',
                    (isset($picker['total_item_count'])) ? $picker['total_item_count'] : '0',
                    (isset($picker['average_picking_time'])) ? $picker['average_picking_time'] : 'No data',
                    (isset($picker['average_picking_time']) && isset($picker['total_product_count'])) ? round(($picker['average_picking_time'] / (int)$picker['total_product_count']), 2) : 'No data',
                    (isset($picker['average_picking_time']) && isset($picker['total_item_count'])) ? round(($picker['average_picking_time'] / (int)$picker['total_item_count']), 2) : 'No data',
                );
                fputcsv($output, $row_data);
            }
        }

        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- Closing direct CSV output stream.
        fclose( $output );
        exit;
    }

    public function  orderpickingapp_loadAnalyticsHTML(){
        check_ajax_referer( 'orderpickingapp_nonce', 'security' );

        $url   = 'https://orderpickingapp.com/wp-json/picking/v1/analytics';
        $token = isset( $_POST['token'] ) ? sanitize_text_field( wp_unslash( $_POST['token'] ) ) : '';

        $response = $this->orderpickingapp_remote_get_json(
            $url,
            array(
                'Authorization' => 'Bearer ' . $token,
                'Referer' => esc_url_raw( home_url() ),
            )
        );

        ob_start();

        if( $response['status'] == '200' ):
            $AnalyticsData = $response['data'];
            ?>
            <div class="row justify-content-center">
                <table class="table table-striped">
                    <tbody>
                    <tr>
                        <td>Average picking orders</td>
                        <td><?php echo esc_html( round( $AnalyticsData['picking_totals_average'] ) ); ?> per month</td>
                    </tr>
                    <tr>
                        <td>Average packing orders</td>
                        <td><?php echo esc_html( round( $AnalyticsData['packing_totals_average'] ) ); ?> per month</td>
                    </tr>
                    <tr>
                        <td>Average active picking time</td>
                        <td><?php echo esc_html( $AnalyticsData['averagePickingTime'] ); ?> last 30 days</td>
                    </tr>
                    <tr>
                        <td>Average order processing time</td>
                        <td><?php echo esc_html( $AnalyticsData['averageOPATime'] ); ?> last 30 days</td>
                    </tr>
                    <tr>
                        <td>Pickers</td>
                        <td>
                            <?php echo esc_html( count( $AnalyticsData['app_users'] ) ); ?>
                        </td>
                    </tr>
                    </tbody>
                </table>

                <div style="display: flex; gap: 20px;">
                    <div style="flex: 1;">
                        <canvas id="pickingChart"></canvas>
                    </div>
                    <div style="flex: 1;">
                        <canvas id="orderItemsChart"></canvas>
                    </div>
                </div>

                <h5 style="margin-top: 40px;">Picker analytics last 30 days</h5>
                <table style="margin-bottom: 40px;" class="table table-striped">
                    <thead>
                    <tr>
                        <td><strong>Picker</strong></td>
                        <td><strong>Total orders</strong></td>
                        <td><strong>Total products</strong></td>
                        <td><strong>Total items</strong></td>
                        <td><strong>Avg. time order (min)</strong></td>
                        <td><strong>Avg. time product (min)</strong></td>
                        <td><strong>Avg. time items (min)</strong></td>
                    </tr>
                    </thead>
                    <tbody>
                    <?php
                    foreach( $AnalyticsData['app_users'] as $picker ):

                        if( $picker['app_users_type'] === 'sales' || $picker['app_users_type'] === 'inventory' ){
                            continue;
                        } ?>
                        <tr>
                            <td><?php echo esc_html( isset( $picker['app_users_name'] ) ? $picker['app_users_name'] : 'Default' ); ?></td>
                            <td><?php echo esc_html( $picker['total_orders'] ); ?></td>
                            <td><?php echo esc_html( isset( $picker['total_product_count'] ) ? $picker['total_product_count'] : '0' ); ?></td>
                            <td><?php echo esc_html( isset( $picker['total_item_count'] ) ? $picker['total_item_count'] : '0' ); ?></td>
                            <td><?php echo esc_html( isset( $picker['average_picking_time'] ) ? $picker['average_picking_time'] : 'No data' ); ?></td>
                            <td><?php echo esc_html( ( isset( $picker['average_picking_time'], $picker['total_product_count'] ) && (int) $picker['total_product_count'] > 0 ) ? round( ( $picker['average_picking_time'] / (int) $picker['total_product_count'] ), 2 ) : 'No data' ); ?></td>
                            <td><?php echo esc_html( ( isset( $picker['average_picking_time'], $picker['total_item_count'] ) && (int) $picker['total_item_count'] > 0 ) ? round( ( $picker['average_picking_time'] / (int) $picker['total_item_count'] ), 2 ) : 'No data' ); ?></td>
                        </tr>
                    <?php endforeach; ?>
                    </tbody>
                </table>

                <div style="display: flex; gap: 20px;">
                    <div style="flex: 1;">
                        <canvas id="pickerChart"></canvas>
                    </div>
                    <div style="flex: 1;">
                        <canvas id="avgPickingTimeChart"></canvas>
                    </div>
                </div>

                <script>
                    const monthNames = <?php echo wp_json_encode($AnalyticsData['past_12_months']); ?>;
                    const pickedValues = <?php echo wp_json_encode($AnalyticsData['past_12_months_picking_totals']); ?>;
                    new Chart("pickingChart", {
                        type: "line",
                        data: {
                            labels: monthNames,
                            datasets: [{
                                label: 'Order amount',
                                fill: false,
                                lineTension: 0,
                                backgroundColor: "rgb(19, 169, 64)",
                                borderColor: "rgb(19, 169, 64)",
                                data: pickedValues
                            }]
                        },
                        options: {
                            plugins: {
                                legend: {
                                    display: false,
                                },
                                title: {
                                    display: true,
                                    text: 'Monthly picked orders'
                                }
                            }
                        }
                    });

                    const pickerValues = <?php echo wp_json_encode($AnalyticsData['past_12_months_picker_totals']); ?>;
                    const datasets = <?php echo wp_json_encode($AnalyticsData['pickerChartDatasets']); ?>;
                    new Chart("pickerChart", {
                        type: "line",
                        data: {
                            labels: monthNames,
                            datasets: datasets
                        },
                        options: {
                            plugins: {
                                legend: {
                                    position: 'top',
                                },
                                title: {
                                    display: true,
                                    text: 'Monthly picked orders by picker (last 30 days)'
                                }
                            }
                        }
                    });

                    var xValues = ["0-10", "10-25", "25-75", "75-150", "150-250", "250+"];
                    var yValues = <?php echo wp_json_encode($AnalyticsData['order_amounts']); ?>;
                    var barColors = ["green", "blue","purple","yellow","orange","red"];
                    new Chart("orderItemsChart", {
                        type: "bar",
                        data: {
                            labels: xValues,
                            datasets: [{
                                label: 'Order items',
                                backgroundColor: barColors,
                                data: yValues
                            }]
                        },
                        options: {
                            plugins: {
                                legend: {
                                    display: false,
                                },
                                title: {
                                    display: true,
                                    text: 'Average order item size (last 30 days)'
                                }
                            }
                        }
                    });

                    const labels = <?php echo wp_json_encode($AnalyticsData['labels']); ?>;
                    const values = <?php echo wp_json_encode($AnalyticsData['values']); ?>;
                    const colors = <?php echo wp_json_encode($AnalyticsData['colors']); ?>;

                    // Optioneel: omzetten van seconden naar minuten en seconden voor labels
                    const formattedValues = values.map(seconds => {
                        const min = Math.floor(seconds / 60);
                        const sec = seconds % 60;
                        return parseFloat((min + sec / 60).toFixed(2)); // Bijvoorbeeld: 2.30 min
                    });

                    new Chart("avgPickingTimeChart", {
                        type: "bar",
                        data: {
                            labels: labels,
                            datasets: [{
                                label: "Avg. picking time (min)",
                                data: formattedValues,
                                backgroundColor: colors,
                                borderColor: colors,
                                borderWidth: 1
                            }]
                        },
                        options: {
                            responsive: true,
                            plugins: {
                                legend: {
                                    display: false,
                                },
                                title: {
                                    display: true,
                                    text: 'Average picking time by picker (last 30 days)'
                                }
                            },
                            scales: {
                                y: {
                                    beginAtZero: true,
                                    title: {
                                        display: true,
                                        text: 'Minutes'
                                    }
                                }
                            }
                        }
                    });
                </script>

            </div>
        <?php else: ?>
            <div class="row justify-content-center">
                <p><?php echo esc_html( $response['message'] ); ?></p>
            </div>
        <?php
        endif;

        $orderpickingapp_analytics_html = ob_get_clean();
        echo $orderpickingapp_analytics_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Buffered analytics markup is escaped inline and contains Chart.js initialization.
    }

    private function orderpickingapp_remote_get_json( $url, $headers = array() ) {
        $response = wp_remote_get(
            esc_url_raw( $url ),
            array(
                'timeout'     => 30,
                'redirection' => 5,
                'headers'     => $headers,
            )
        );

        if ( is_wp_error( $response ) ) {
            return false;
        }

        $status_code = wp_remote_retrieve_response_code( $response );

        if ( 200 > $status_code || 299 < $status_code ) {
            return false;
        }

        $body = wp_remote_retrieve_body( $response );

        if ( empty( $body ) ) {
            return false;
        }

        return json_decode( $body, true );
    }

}

