<?php
/**
 * GGM Commerce Barcode Management Class
 * Handles barcode operations for products
 */

// Prevent direct access
if (!defined('ABSPATH')) {
    exit;
}

class GGM_Commerce_Barcode {

    private static $instance = null;

    public static function get_instance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * Supported barcode types
     */
    public function get_barcode_types() {
        return [
            'EAN-13' => 'EAN-13 (European Article Number)',
            'EAN-8' => 'EAN-8',
            'UPC-A' => 'UPC-A (Universal Product Code)',
            'UPC-E' => 'UPC-E',
            'ISBN' => 'ISBN (International Standard Book Number)',
            'CODE-39' => 'Code 39',
            'CODE-128' => 'Code 128',
            'ITF-14' => 'ITF-14',
            'QR' => 'QR Code',
            'OTHER' => 'Other'
        ];
    }

    /**
     * Get all barcodes for a product
     */
    public function get_product_barcodes($product_id) {
        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        return $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM {$wpdb->prefix}ggmc_product_barcodes
             WHERE product_id = %d
             ORDER BY is_primary DESC, id ASC",
            $product_id
        ));
    }

    /**
     * Get primary barcode for a product
     */
    public function get_primary_barcode($product_id) {
        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $barcode = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM {$wpdb->prefix}ggmc_product_barcodes
             WHERE product_id = %d AND is_primary = 1
             LIMIT 1",
            $product_id
        ));

        // If no primary barcode, return first barcode
        if (!$barcode) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $barcode = $wpdb->get_row($wpdb->prepare(
                "SELECT * FROM {$wpdb->prefix}ggmc_product_barcodes
                 WHERE product_id = %d
                 ORDER BY id ASC
                 LIMIT 1",
                $product_id
            ));
        }

        return $barcode;
    }

    /**
     * Add barcode to product
     */
    public function add_barcode($product_id, $barcode_value, $barcode_type = 'EAN-13', $is_primary = false) {
        global $wpdb;

        // Validate barcode doesn't already exist
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $exists = $wpdb->get_var($wpdb->prepare(
            "SELECT id FROM {$wpdb->prefix}ggmc_product_barcodes WHERE barcode_value = %s",
            $barcode_value
        ));

        if ($exists) {
            return new WP_Error('duplicate_barcode', 'This barcode already exists in the system');
        }

        // Check if product already has 3 barcodes (limit)
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $count = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM {$wpdb->prefix}ggmc_product_barcodes WHERE product_id = %d",
            $product_id
        ));

        if ($count >= 3) {
            return new WP_Error('barcode_limit', 'Products can have a maximum of 3 barcodes');
        }

        // If this is set as primary, unset others
        if ($is_primary) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $wpdb->update(
                "{$wpdb->prefix}ggmc_product_barcodes",
                ['is_primary' => 0],
                ['product_id' => $product_id]
            );
        }

        // Insert barcode
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $result = $wpdb->insert(
            "{$wpdb->prefix}ggmc_product_barcodes",
            [
                'product_id' => $product_id,
                'barcode_value' => $barcode_value,
                'barcode_type' => $barcode_type,
                'is_primary' => $is_primary ? 1 : 0,
                'created_at' => current_time('mysql')
            ],
            ['%d', '%s', '%s', '%d', '%s']
        );

        if ($result === false) {
            return new WP_Error('db_error', 'Failed to add barcode');
        }

        return $wpdb->insert_id;
    }

    /**
     * Update barcode
     */
    public function update_barcode($barcode_id, $barcode_value, $barcode_type, $is_primary = false) {
        global $wpdb;

        // Get barcode to check product_id
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $barcode = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM {$wpdb->prefix}ggmc_product_barcodes WHERE id = %d",
            $barcode_id
        ));

        if (!$barcode) {
            return new WP_Error('not_found', 'Barcode not found');
        }

        // Check if value changed and if new value already exists
        if ($barcode->barcode_value !== $barcode_value) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $exists = $wpdb->get_var($wpdb->prepare(
                "SELECT id FROM {$wpdb->prefix}ggmc_product_barcodes
                 WHERE barcode_value = %s AND id != %d",
                $barcode_value,
                $barcode_id
            ));

            if ($exists) {
                return new WP_Error('duplicate_barcode', 'This barcode already exists in the system');
            }
        }

        // If this is set as primary, unset others for this product
        if ($is_primary) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $wpdb->update(
                "{$wpdb->prefix}ggmc_product_barcodes",
                ['is_primary' => 0],
                ['product_id' => $barcode->product_id]
            );
        }

        // Update barcode
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $result = $wpdb->update(
            "{$wpdb->prefix}ggmc_product_barcodes",
            [
                'barcode_value' => $barcode_value,
                'barcode_type' => $barcode_type,
                'is_primary' => $is_primary ? 1 : 0,
                'updated_at' => current_time('mysql')
            ],
            ['id' => $barcode_id],
            ['%s', '%s', '%d', '%s'],
            ['%d']
        );

        if ($result === false) {
            return new WP_Error('db_error', 'Failed to update barcode');
        }

        return true;
    }

    /**
     * Delete barcode
     */
    public function delete_barcode($barcode_id) {
        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $result = $wpdb->delete(
            "{$wpdb->prefix}ggmc_product_barcodes",
            ['id' => $barcode_id],
            ['%d']
        );

        if ($result === false) {
            return new WP_Error('db_error', 'Failed to delete barcode');
        }

        return true;
    }

    /**
     * Set barcode as primary
     */
    public function set_primary($barcode_id) {
        global $wpdb;

        // Get barcode to check product_id
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $barcode = $wpdb->get_row($wpdb->prepare(
            "SELECT product_id FROM {$wpdb->prefix}ggmc_product_barcodes WHERE id = %d",
            $barcode_id
        ));

        if (!$barcode) {
            return new WP_Error('not_found', 'Barcode not found');
        }

        // Unset all primary for this product
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $wpdb->update(
            "{$wpdb->prefix}ggmc_product_barcodes",
            ['is_primary' => 0],
            ['product_id' => $barcode->product_id]
        );

        // Set this one as primary
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $result = $wpdb->update(
            "{$wpdb->prefix}ggmc_product_barcodes",
            ['is_primary' => 1],
            ['id' => $barcode_id]
        );

        return $result !== false;
    }

    /**
     * Find product by barcode
     */
    public function find_product_by_barcode($barcode_value) {
        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        return $wpdb->get_row($wpdb->prepare(
            "SELECT p.* FROM {$wpdb->prefix}ggmc_products p
             INNER JOIN {$wpdb->prefix}ggmc_product_barcodes b ON p.id = b.product_id
             WHERE b.barcode_value = %s
             LIMIT 1",
            $barcode_value
        ));
    }

    /**
     * Search products by barcode (partial match)
     */
    public function search_by_barcode($search_term) {
        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        return $wpdb->get_results($wpdb->prepare(
            "SELECT DISTINCT p.*, b.barcode_value
             FROM {$wpdb->prefix}ggmc_products p
             INNER JOIN {$wpdb->prefix}ggmc_product_barcodes b ON p.id = b.product_id
             WHERE b.barcode_value LIKE %s
             ORDER BY p.name ASC
             LIMIT 20",
            '%' . $wpdb->esc_like($search_term) . '%'
        ));
    }

    /**
     * Bulk save barcodes for a product
     * Expects array of barcodes: [['value' => '123', 'type' => 'EAN-13', 'is_primary' => true], ...]
     */
    public function save_product_barcodes($product_id, $barcodes) {
        global $wpdb;

        // Start transaction
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $wpdb->query('START TRANSACTION');

        try {
            // Get existing barcodes
            $existing_barcodes = $this->get_product_barcodes($product_id);
            $existing_ids = array_column($existing_barcodes, 'id');

            $saved_ids = [];

            foreach ($barcodes as $index => $barcode_data) {
                if (empty($barcode_data['value'])) {
                    continue; // Skip empty barcodes
                }

                $barcode_value = sanitize_text_field($barcode_data['value']);
                $barcode_type = sanitize_text_field($barcode_data['type'] ?? 'EAN-13');
                $is_primary = !empty($barcode_data['is_primary']);
                $barcode_id = intval($barcode_data['id'] ?? 0);

                // Update existing or create new
                if ($barcode_id > 0 && in_array($barcode_id, $existing_ids)) {
                    // Update existing barcode
                    $result = $this->update_barcode($barcode_id, $barcode_value, $barcode_type, $is_primary);
                    if (is_wp_error($result)) {
                        throw new Exception($result->get_error_message());
                    }
                    $saved_ids[] = $barcode_id;
                } else {
                    // Add new barcode
                    $result = $this->add_barcode($product_id, $barcode_value, $barcode_type, $is_primary);
                    if (is_wp_error($result)) {
                        throw new Exception($result->get_error_message());
                    }
                    $saved_ids[] = $result;
                }
            }

            // Delete barcodes that weren't in the save list
            foreach ($existing_ids as $existing_id) {
                if (!in_array($existing_id, $saved_ids)) {
                    $this->delete_barcode($existing_id);
                }
            }

            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $wpdb->query('COMMIT');
            return true;

        } catch (Exception $e) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $wpdb->query('ROLLBACK');
            return new WP_Error('save_failed', $e->getMessage());
        }
    }
}

// Initialize barcode class
GGM_Commerce_Barcode::get_instance();
