<?php
/**
 * Bizmart Core - Barcodes Management Suite
 */

if (!defined('ABSPATH')) exit;

// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter

/**
 * Perform database table checks on init
 */
function bizmart_barcodes_db_install() {
    global $wpdb;
    $table_name = $wpdb->prefix . 'bizmart_product_barcodes';
    // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
    $exists = $wpdb->get_var("SHOW TABLES LIKE '{$table_name}'") === $table_name;
    // phpcs:enable
    
    // Check if table exists
    if (!$exists) {
        $charset_collate = $wpdb->get_charset_collate();
        
        $sql = "CREATE TABLE {$table_name} (
            id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
            product_id bigint(20) UNSIGNED NOT NULL,
            barcode varchar(100) NOT NULL,
            barcode_format varchar(20) NOT NULL DEFAULT 'CODE128',
            label varchar(100) DEFAULT '',
            is_primary tinyint(1) NOT NULL DEFAULT 0,
            created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
            updated_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
            PRIMARY KEY (id),
            UNIQUE KEY unique_barcode (barcode),
            KEY product_id_idx (product_id),
            KEY primary_lookup_idx (product_id, is_primary)
        ) $charset_collate;";
        
        require_once ABSPATH . 'wp-admin/includes/upgrade.php';
        dbDelta($sql);
    }
}
add_action('init', 'bizmart_barcodes_db_install');

/**
 * EAN-13 check digit calculator
 */
function bizmart_validate_ean13(string $barcode): bool {
    if (!preg_match('/^\d{13}$/', $barcode)) {
        return false;
    }
    
    $odd_sum = 0;
    $even_sum = 0;
    for ($i = 0; $i < 12; $i++) {
        $digit = (int) $barcode[$i];
        if ($i % 2 === 0) {
            $odd_sum += $digit;
        } else {
            $even_sum += $digit;
        }
    }
    
    $total = $odd_sum + ($even_sum * 3);
    $check_digit = (10 - ($total % 10)) % 10;
    
    return $check_digit === (int) $barcode[12];
}

/**
 * Generate internal EAN-13 code
 */
function bizmart_generate_internal_barcode(int $product_id): string {
    $prefix = '290'; 
    $formatted_product_id = str_pad((string) $product_id, 9, '0', STR_PAD_LEFT);
    $base_digits = $prefix . $formatted_product_id;
    
    $odd_sum = 0;
    $even_sum = 0;
    for ($i = 0; $i < 12; $i++) {
        $digit = (int) $base_digits[$i];
        if ($i % 2 === 0) {
            $odd_sum += $digit;
        } else {
            $even_sum += $digit;
        }
    }
    $total = $odd_sum + ($even_sum * 3);
    $check_digit = (10 - ($total % 10)) % 10;
    
    return $base_digits . $check_digit;
}

/**
 * Resolve barcode query
 */
function bizmart_resolve_barcode(string $barcode): ?array {
    global $wpdb;
    
    $clean_barcode = sanitize_text_field(trim($barcode));
    if (empty($clean_barcode)) {
        return null;
    }
    
    $table = $wpdb->prefix . 'bizmart_product_barcodes';
    // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
    $row = $wpdb->get_row($wpdb->prepare(
        "SELECT product_id, barcode_format, is_primary FROM {$table} WHERE barcode = %s LIMIT 1",
        $clean_barcode
    ));
    // phpcs:enable
    
    if (!$row) {
        $product_id = wc_get_product_id_by_sku($clean_barcode);
        if ($product_id) {
            $row = (object) [
                'product_id' => $product_id,
                'barcode_format' => 'CODE128',
                'is_primary' => 1
            ];
        }
    }
    
    if (!$row) {
        // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $product_id = $wpdb->get_var($wpdb->prepare(
            "SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = '_barcode' AND meta_value = %s LIMIT 1",
            $clean_barcode
        ));
        // phpcs:enable
        if ($product_id) {
            $row = (object) [
                'product_id' => $product_id,
                'barcode_format' => 'CODE128',
                'is_primary' => 1
            ];
        }
    }
    
    if (!$row) {
        return null;
    }
    
    $product = wc_get_product($row->product_id);
    if (!$product) {
        return null;
    }
    
    return [
        'product_id'     => (int) $row->product_id,
        'parent_id'      => $product->get_parent_id() ?: (int) $row->product_id,
        'is_variation'   => $product->is_type('variation'),
        'barcode_format' => $row->barcode_format,
        'sku'            => $product->get_sku(),
        'price'          => (float) $product->get_price(),
        'name'           => $product->get_name(),
    ];
}

/**
 * Handle saving barcodes on WooCommerce simple / variable save
 */
function bizmart_save_product_barcodes(int $post_id) {
    global $wpdb;
    $table = $wpdb->prefix . 'bizmart_product_barcodes';
    
    // phpcs:disable WordPress.Security.NonceVerification.Missing, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    // Process simple product barcode array changes
    if (isset($_POST['biz_barcode_val']) && is_array($_POST['biz_barcode_val'])) {
        $values = map_deep(wp_unslash($_POST['biz_barcode_val']), 'sanitize_text_field');
        $formats = isset($_POST['biz_barcode_fmt']) ? map_deep(wp_unslash($_POST['biz_barcode_fmt']), 'sanitize_text_field') : [];
        $labels = isset($_POST['biz_barcode_lbl']) ? map_deep(wp_unslash($_POST['biz_barcode_lbl']), 'sanitize_text_field') : [];
        $primary_id = isset($_POST['biz_barcode_primary']) ? sanitize_text_field(wp_unslash($_POST['biz_barcode_primary'])) : '';
        
        // Clear old ones
        $wpdb->delete($table, ['product_id' => $post_id]);
        
        foreach ($values as $temp_id => $barcode_val) {
            $barcode_val = sanitize_text_field(trim($barcode_val));
            if (empty($barcode_val)) continue;
            
            $format = sanitize_text_field($formats[$temp_id] ?? 'CODE128');
            $label = sanitize_text_field($labels[$temp_id] ?? '');
            $is_primary = ($temp_id === $primary_id) ? 1 : 0;
            
            if ($format === 'EAN13' && !bizmart_validate_ean13($barcode_val)) {
                // Ignore invalid EAN digit strings silently to let it skip
                continue;
            }
            
            $wpdb->insert($table, [
                'product_id' => $post_id,
                'barcode' => $barcode_val,
                'barcode_format' => $format,
                'label' => $label,
                'is_primary' => $is_primary
            ]);
        }
    }
    // phpcs:enable
}
add_action('woocommerce_process_product_meta', 'bizmart_save_product_barcodes');
add_action('woocommerce_save_product_variation', 'bizmart_save_product_barcodes');

/**
 * Add custom barcode tab to WooCommerce product data tabs
 */
function bizmart_add_barcodes_product_tab(array $tabs): array {
    $tabs['bizmart_barcodes'] = [
        'label'    => __('Product Barcodes', 'bizmart-cost-of-goods'),
        'target'   => 'bizmart_barcodes_data',
        'class'    => ['show_if_simple', 'show_if_variable'],
        'priority' => 70,
    ];
    return $tabs;
}

/**
 * Render custom barcode panel in WooCommerce product data panels
 */
function bizmart_render_barcodes_data_panel() {
    global $post, $wpdb;
    
    $product_id = $post->ID;
    $table = $wpdb->prefix . 'bizmart_product_barcodes';
    
    // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
    // Fetch existing barcodes
    $barcodes = $wpdb->get_results($wpdb->prepare(
        "SELECT * FROM {$table} WHERE product_id = %d ORDER BY is_primary DESC, id ASC",
        $product_id
    ));
    // phpcs:enable
    
    ?>
    <div id="bizmart_barcodes_data" class="panel woocommerce_options_panel hidden">
        <div class="options_group">
            <h3><?php esc_html_e('Manage Barcodes', 'bizmart-cost-of-goods'); ?></h3>
            <p class="form-field"><?php esc_html_e('Add multiple barcodes to this product/variation (e.g., EAN-13, CODE128).', 'bizmart-cost-of-goods'); ?></p>
            
            <table class="widefat striped" id="bizmart-barcodes-table" style="margin: 10px 0; max-width: 800px;">
                <thead>
                    <tr>
                        <th style="width: 40%;"><?php esc_html_e('Barcode', 'bizmart-cost-of-goods'); ?></th>
                        <th style="width: 25%;"><?php esc_html_e('Format', 'bizmart-cost-of-goods'); ?></th>
                        <th style="width: 25%;"><?php esc_html_e('Label (e.g., Package, Unit)', 'bizmart-cost-of-goods'); ?></th>
                        <th style="width: 5%; text-align: center;"><?php esc_html_e('Primary', 'bizmart-cost-of-goods'); ?></th>
                        <th style="width: 5%; text-align: center;"></th>
                    </tr>
                </thead>
                <tbody>
                    <?php if (!empty($barcodes)) : ?>
                        <?php foreach ($barcodes as $barcode) : ?>
                            <tr class="barcode-row">
                                <td>
                                    <input type="text" name="biz_barcode_val[<?php echo esc_attr($barcode->id); ?>]" value="<?php echo esc_attr($barcode->barcode); ?>" class="input-text" style="width: 100%;" required />
                                </td>
                                <td>
                                    <select name="biz_barcode_fmt[<?php echo esc_attr($barcode->id); ?>]" style="width: 100%;">
                                        <option value="CODE128" <?php selected($barcode->barcode_format, 'CODE128'); ?>>CODE128</option>
                                        <option value="EAN13" <?php selected($barcode->barcode_format, 'EAN13'); ?>>EAN-13</option>
                                    </select>
                                </td>
                                <td>
                                    <input type="text" name="biz_barcode_lbl[<?php echo esc_attr($barcode->id); ?>]" value="<?php echo esc_attr($barcode->label); ?>" class="input-text" style="width: 100%;" />
                                </td>
                                <td style="text-align: center;">
                                    <input type="radio" name="biz_barcode_primary" value="<?php echo esc_attr($barcode->id); ?>" <?php checked($barcode->is_primary, 1); ?> />
                                </td>
                                <td style="text-align: center;">
                                    <button type="button" class="button remove-barcode-row" style="color: #a00;">&times;</button>
                                </td>
                            </tr>
                        <?php endforeach; ?>
                    <?php else : ?>
                        <tr class="no-barcodes-placeholder">
                            <td colspan="5" style="text-align: center; color: #777; padding: 20px 0;">
                                <?php esc_html_e('No custom barcodes configured yet.', 'bizmart-cost-of-goods'); ?>
                            </td>
                        </tr>
                    <?php endif; ?>
                </tbody>
            </table>
            
            <p>
                <button type="button" class="button button-primary" id="add-new-barcode-row"><?php esc_html_e('Add Barcode', 'bizmart-cost-of-goods'); ?></button>
                <button type="button" class="button" id="generate-internal-ean"><?php esc_html_e('Generate EAN-13', 'bizmart-cost-of-goods'); ?></button>
            </p>
        </div>
    </div>
    
    <script type="text/javascript">
    jQuery(document).ready(function($) {
        var $table = $('#bizmart-barcodes-table tbody');
        
        function getUniqueTempId() {
            return 'temp_' + new Date().getTime() + '_' + Math.floor(Math.random() * 1000);
        }
        
        $('#add-new-barcode-row').on('click', function(e) {
            e.preventDefault();
            $table.find('.no-barcodes-placeholder').remove();
            
            var tempId = getUniqueTempId();
            var rowHtml = '<tr class="barcode-row">' +
                '<td><input type="text" name="biz_barcode_val[' + tempId + ']" value="" class="input-text" style="width: 100%;" required /></td>' +
                '<td>' +
                    '<select name="biz_barcode_fmt[' + tempId + ']" style="width: 100%;">' +
                        '<option value="CODE128">CODE128</option>' +
                        '<option value="EAN13">EAN-13</option>' +
                    '</select>' +
                '</td>' +
                '<td><input type="text" name="biz_barcode_lbl[' + tempId + ']" value="" class="input-text" style="width: 100%;" /></td>' +
                '<td style="text-align: center;"><input type="radio" name="biz_barcode_primary" value="' + tempId + '" /></td>' +
                '<td style="text-align: center;"><button type="button" class="button remove-barcode-row" style="color: #a00;">&times;</button></td>' +
            '</tr>';
            
            $table.append(rowHtml);
            
            // Check if there is only one radio button, make it checked
            var $radios = $table.find('input[type="radio"]');
            if ($radios.length === 1 || !$radios.filter(':checked').length) {
                $radios.first().prop('checked', true);
            }
        });
        
        $('#generate-internal-ean').on('click', function(e) {
            e.preventDefault();
            
            var productId = $('#post_ID').val();
            if (!productId) {
                alert('Product ID not found. Please save the product first.');
                return;
            }
            
            // Call generate_internal_barcode via AJAX helper or calculate client-side
            // Since we already have bizmart_generate_internal_barcode in PHP, we can generate a temporary EAN-13 client-side
            // using prefix 290 + padded product ID + check digit to avoid a network round-trip.
            var prefix = '290';
            var formattedId = String(productId).padStart(9, '0');
            var base = prefix + formattedId;
            var oddSum = 0;
            var evenSum = 0;
            for (var i = 0; i < 12; i++) {
                var digit = parseInt(base[i], 10);
                if (i % 2 === 0) {
                    oddSum += digit;
                } else {
                    evenSum += digit;
                }
            }
            var total = oddSum + (evenSum * 3);
            var checkDigit = (10 - (total % 10)) % 10;
            var ean = base + checkDigit;
            
            $table.find('.no-barcodes-placeholder').remove();
            var tempId = getUniqueTempId();
            
            var rowHtml = '<tr class="barcode-row">' +
                '<td><input type="text" name="biz_barcode_val[' + tempId + ']" value="' + ean + '" class="input-text" style="width: 100%;" required /></td>' +
                '<td>' +
                    '<select name="biz_barcode_fmt[' + tempId + ']" style="width: 100%;">' +
                        '<option value="EAN13" selected>EAN-13</option>' +
                        '<option value="CODE128">CODE128</option>' +
                    '</select>' +
                '</td>' +
                '<td><input type="text" name="biz_barcode_lbl[' + tempId + ']" value="Auto Generated" class="input-text" style="width: 100%;" /></td>' +
                '<td style="text-align: center;"><input type="radio" name="biz_barcode_primary" value="' + tempId + '" /></td>' +
                '<td style="text-align: center;"><button type="button" class="button remove-barcode-row" style="color: #a00;">&times;</button></td>' +
            '</tr>';
            
            $table.append(rowHtml);
            
            var $radios = $table.find('input[type="radio"]');
            if ($radios.length === 1 || !$radios.filter(':checked').length) {
                $radios.first().prop('checked', true);
            }
        });
        
        $table.on('click', '.remove-barcode-row', function(e) {
            e.preventDefault();
            var $row = $(this).closest('tr');
            var wasChecked = $row.find('input[type="radio"]').is(':checked');
            
            $row.remove();
            
            if (wasChecked) {
                $table.find('input[type="radio"]').first().prop('checked', true);
            }
            
            if ($table.find('.barcode-row').length === 0) {
                $table.append('<tr class="no-barcodes-placeholder"><td colspan="5" style="text-align: center; color: #777; padding: 20px 0;">No custom barcodes configured yet.</td></tr>');
            }
        });
    });
    </script>
    <?php
}

/**
 * Fetch barcodes for a product or variation
 */
function bizmart_get_product_barcodes(int $product_id): array {
    global $wpdb;
    $table = $wpdb->prefix . 'bizmart_product_barcodes';
    // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
    $results = $wpdb->get_results($wpdb->prepare(
        "SELECT id, barcode, barcode_format, label, is_primary FROM {$table} WHERE product_id = %d ORDER BY is_primary DESC, id ASC",
        $product_id
    ), ARRAY_A);
    // phpcs:enable
    return $results ?: [];
}

/**
 * AJAX handler to generate a unique internal EAN-13 barcode
 */
add_action('wp_ajax_bizmart_generate_barcode', function() {
    // Basic permissions check
    if (!current_user_can('manage_woocommerce')) {
        wp_send_json_error('Unauthorized');
    }

    global $wpdb;
    $table = $wpdb->prefix . 'bizmart_product_barcodes';
    
    $attempts = 0;
    while ($attempts < 100) {
        $random_part = '';
        for ($i = 0; $i < 9; $i++) {
            $random_part .= wp_rand(0, 9);
        }
        $base_digits = '290' . $random_part;
        
        // Calculate check digit
        $odd_sum = 0;
        $even_sum = 0;
        for ($i = 0; $i < 12; $i++) {
            $digit = (int) $base_digits[$i];
            if ($i % 2 === 0) {
                $odd_sum += $digit;
            } else {
                $even_sum += $digit;
            }
        }
        $total = $odd_sum + ($even_sum * 3);
        $check_digit = (10 - ($total % 10)) % 10;
        $barcode = $base_digits . $check_digit;
        
        // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        // Ensure unique
        $exists = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM {$table} WHERE barcode = %s",
            $barcode
        ));
        // phpcs:enable
        
        if (!$exists) {
            wp_send_json_success(['barcode' => $barcode]);
            return;
        }
        $attempts++;
    }
    wp_send_json_error('Could not generate unique barcode');
});

/**
 * Synchronize barcodes for a product or variation in a transaction-safe manner
 */
function bizmart_sync_product_barcodes(int $product_id, array $barcodes): void {
    global $wpdb;
    $table = $wpdb->prefix . 'bizmart_product_barcodes';
    
    // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
    $wpdb->query('START TRANSACTION');
    try {
        $wpdb->delete($table, ['product_id' => $product_id]);
        
        foreach ($barcodes as $b) {
            $barcode_val = sanitize_text_field(trim($b['barcode'] ?? ''));
            if (empty($barcode_val)) continue;
            
            $format = sanitize_text_field($b['barcode_format'] ?? $b['type'] ?? 'CODE128');
            $label = sanitize_text_field($b['label'] ?? '');
            $is_primary = (!empty($b['is_primary']) || !empty($b['primary'])) ? 1 : 0;
            
            $wpdb->insert($table, [
                'product_id' => $product_id,
                'barcode' => $barcode_val,
                'barcode_format' => $format,
                'label' => $label,
                'is_primary' => $is_primary
            ]);
        }
        $wpdb->query('COMMIT');
    } catch (Exception $e) {
        $wpdb->query('ROLLBACK');
    }
    // phpcs:enable
}



