<?php
/**
 * GGM Commerce JSON Exporter
 *
 * Comprehensive JSON export for full backup/migration
 * Exports all product-related entities with complete metadata
 *
 * @package GGM_Commerce
 * @since 1.0.0
 */

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

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

class GGM_Commerce_JSON_Exporter {

    /**
     * Export format version
     */
    const FORMAT_VERSION = '2.0';

    /**
     * Export options
     * @var array
     */
    private $options = [];

    /**
     * Image manifest for separate image package
     * @var array
     */
    private $image_manifest = [];

    /**
     * Constructor
     */
    public function __construct() {
        $this->options = [
            'include_tax_rates' => true,
            'include_attribute_groups' => true,
            'include_attributes' => true,
            'include_variation_attributes' => true,
            'include_categories' => true,
            'include_tags' => true,
            'include_products' => true,
            'include_variations' => true,
            'include_barcodes' => true,
            'include_downloads' => true,
            'include_kits' => true,
            'export_image_package' => false,
            'include_trashed' => false,
        ];
    }

    /**
     * Set export options
     *
     * @param array $options Options to set
     */
    public function set_options($options) {
        $this->options = wp_parse_args($options, $this->options);
    }

    /**
     * Export all data to JSON
     *
     * @param array $product_ids Optional specific product IDs to export
     * @return array Export data structure
     */
    public function export($product_ids = []) {
        global $wpdb;

        $export_data = [
            'meta' => $this->build_meta($product_ids),
        ];

        // Export supporting entities first (these have no dependencies)
        if ($this->options['include_tax_rates']) {
            $export_data['tax_rates'] = $this->export_tax_rates();
        }

        if ($this->options['include_attribute_groups']) {
            $export_data['attribute_groups'] = $this->export_attribute_groups();
        }

        if ($this->options['include_attributes']) {
            $export_data['attributes'] = $this->export_attributes();
        }

        if ($this->options['include_variation_attributes']) {
            $export_data['variation_attribute_groups'] = $this->export_variation_attribute_groups();
            $export_data['variation_attributes'] = $this->export_variation_attributes();
        }

        if ($this->options['include_categories']) {
            $export_data['categories'] = $this->export_categories();
        }

        if ($this->options['include_tags']) {
            $export_data['tags'] = $this->export_tags();
        }

        // Export products (depends on all above)
        if ($this->options['include_products']) {
            $export_data['products'] = $this->export_products($product_ids);
        }

        // Add image manifest if exporting image package
        if ($this->options['export_image_package']) {
            $export_data['image_manifest'] = $this->image_manifest;
        }

        return $export_data;
    }

    /**
     * Build export metadata
     *
     * @param array $product_ids Product IDs being exported
     * @return array Meta information
     */
    private function build_meta($product_ids) {
        global $wpdb;

        // Count entities
        $excluded_statuses = "'deleted'";
        if (empty($this->options['include_trashed'])) {
            $excluded_statuses .= ", 'trash'";
        }
        $product_count = empty($product_ids)
            ? $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}ggmc_products WHERE status NOT IN ({$excluded_statuses})")
            : count($product_ids);

        return [
            'format_version' => self::FORMAT_VERSION,
            'plugin_version' => defined('GGM_COMMERCE_VERSION') ? GGM_COMMERCE_VERSION : '1.0.0',
            'exported_at' => current_time('c'),
            'site_url' => get_site_url(),
            'counts' => [
                'products' => (int) $product_count,
                'categories' => (int) $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}ggmc_categories WHERE status = 'active'"),
                'tags' => (int) $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}ggmc_tags WHERE status = 'active'"),
                'attribute_groups' => (int) $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}ggmc_attribute_groups WHERE status = 'active'"),
                'attributes' => (int) $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}ggmc_attributes WHERE status = 'active'"),
                'variation_attributes' => (int) $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}ggmc_variation_types WHERE status = 'active'"),
                'tax_rates' => (int) $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}ggmc_tax_rates WHERE status = 'active'"),
            ],
            'images_included' => $this->options['export_image_package'],
        ];
    }

    /**
     * Export tax rates
     *
     * @return array Tax rates data
     */
    private function export_tax_rates() {
        global $wpdb;

        $rates = $wpdb->get_results(
            "SELECT name, slug, rate, description, is_default, display_order, status
             FROM {$wpdb->prefix}ggmc_tax_rates
             WHERE status = 'active'
             ORDER BY display_order, name",
            ARRAY_A
        );

        return array_map(function($rate) {
            return [
                'name' => $rate['name'],
                'slug' => $rate['slug'],
                'rate' => (float) $rate['rate'],
                'description' => $rate['description'] ?: '',
                'is_default' => (bool) $rate['is_default'],
                'display_order' => (int) $rate['display_order'],
                'status' => $rate['status'],
            ];
        }, $rates ?: []);
    }

    /**
     * Export attribute groups
     *
     * @return array Attribute groups data
     */
    private function export_attribute_groups() {
        global $wpdb;

        $groups = $wpdb->get_results(
            "SELECT name, description, display_order, status
             FROM {$wpdb->prefix}ggmc_attribute_groups
             WHERE status = 'active'
             ORDER BY display_order, name",
            ARRAY_A
        );

        return array_map(function($group) {
            return [
                'name' => $group['name'],
                'description' => $group['description'] ?: '',
                'display_order' => (int) $group['display_order'],
                'status' => $group['status'],
            ];
        }, $groups ?: []);
    }

    /**
     * Export attributes with full metadata
     *
     * @return array Attributes data
     */
    private function export_attributes() {
        global $wpdb;

        $attributes = $wpdb->get_results(
            "SELECT a.*, ag.name as group_name
             FROM {$wpdb->prefix}ggmc_attributes a
             LEFT JOIN {$wpdb->prefix}ggmc_attribute_groups ag ON a.group_id = ag.id
             WHERE a.status = 'active'
             ORDER BY a.display_order, a.name",
            ARRAY_A
        );

        return array_map(function($attr) {
            $options = $attr['options'];
            if (!empty($options)) {
                $decoded = json_decode($options, true);
                $options = is_array($decoded) ? $decoded : [];
            } else {
                $options = [];
            }

            return [
                'name' => $attr['name'],
                'group' => $attr['group_name'] ?: null,
                'attribute_type' => $attr['attribute_type'] ?: 'text',
                'options' => $options,
                'unit' => $attr['unit'] ?: '',
                'icon' => $attr['icon'] ?: '',
                'display_order' => (int) $attr['display_order'],
                'status' => $attr['status'],
            ];
        }, $attributes ?: []);
    }

    /**
     * Export variation attribute groups
     *
     * @return array Variation attribute groups data
     */
    private function export_variation_attribute_groups() {
        global $wpdb;

        $groups = $wpdb->get_results(
            "SELECT id, name, slug, description, is_suggestion, display_order, status
             FROM {$wpdb->prefix}ggmc_variation_type_groups
             WHERE status = 'active'
             ORDER BY display_order, name",
            ARRAY_A
        );

        // Get types for each group
        return array_map(function($group) use ($wpdb) {
            $types = $wpdb->get_col($wpdb->prepare(
                "SELECT vt.name
                 FROM {$wpdb->prefix}ggmc_variation_type_group_members vtgm
                 INNER JOIN {$wpdb->prefix}ggmc_variation_types vt ON vtgm.variation_type_id = vt.id
                 WHERE vtgm.group_id = %d
                 ORDER BY vtgm.display_order",
                $group['id']
            ));

            return [
                'name' => $group['name'],
                'slug' => $group['slug'],
                'description' => $group['description'] ?: '',
                'is_suggestion' => (bool) $group['is_suggestion'],
                'display_order' => (int) $group['display_order'],
                'status' => $group['status'],
                'attributes' => $types ?: [],
            ];
        }, $groups ?: []);
    }

    /**
     * Export variation types
     *
     * @return array Variation types data
     */
    private function export_variation_attributes() {
        global $wpdb;

        $types = $wpdb->get_results(
            "SELECT name, slug, input_type, options, display_order, status
             FROM {$wpdb->prefix}ggmc_variation_types
             WHERE status = 'active'
             ORDER BY display_order, name",
            ARRAY_A
        );

        return array_map(function($type) {
            $options = $type['options'];
            if (!empty($options)) {
                $decoded = json_decode($options, true);
                $options = is_array($decoded) ? $decoded : [];
            } else {
                $options = [];
            }

            return [
                'name' => $type['name'],
                'slug' => $type['slug'],
                'input_type' => $type['input_type'] ?: 'select',
                'options' => $options,
                'display_order' => (int) $type['display_order'],
                'status' => $type['status'],
            ];
        }, $types ?: []);
    }

    /**
     * Export categories with hierarchy
     *
     * @return array Categories data with nested children
     */
    private function export_categories() {
        global $wpdb;

        // Get all categories
        $categories = $wpdb->get_results(
            "SELECT id, name, slug, description, parent_id, display_order, image_id, status
             FROM {$wpdb->prefix}ggmc_categories
             WHERE status = 'active'
             ORDER BY parent_id, display_order, name",
            ARRAY_A
        );

        if (empty($categories)) {
            return [];
        }

        // Build hierarchy
        $indexed = [];
        foreach ($categories as $cat) {
            $indexed[$cat['id']] = $cat;
            $indexed[$cat['id']]['children'] = [];
        }

        $tree = [];
        foreach ($indexed as $id => &$cat) {
            if (empty($cat['parent_id']) || !isset($indexed[$cat['parent_id']])) {
                $tree[] = &$cat;
            } else {
                $indexed[$cat['parent_id']]['children'][] = &$cat;
            }
        }

        // Convert to export format recursively
        return $this->format_category_tree($tree);
    }

    /**
     * Format category tree for export
     *
     * @param array $categories Categories array
     * @return array Formatted categories
     */
    private function format_category_tree($categories) {
        $result = [];

        foreach ($categories as $cat) {
            $image = $this->get_image_data($cat['image_id'], 'categories', $cat['slug']);

            $formatted = [
                'name' => $cat['name'],
                'slug' => $cat['slug'],
                'description' => $cat['description'] ?: '',
                'image' => $image,
                'display_order' => (int) $cat['display_order'],
                'status' => $cat['status'],
                'children' => !empty($cat['children']) ? $this->format_category_tree($cat['children']) : [],
            ];

            $result[] = $formatted;
        }

        return $result;
    }

    /**
     * Export tags
     *
     * @return array Tags data
     */
    private function export_tags() {
        global $wpdb;

        $tags = $wpdb->get_results(
            "SELECT name, slug, description, status
             FROM {$wpdb->prefix}ggmc_tags
             WHERE status = 'active'
             ORDER BY name",
            ARRAY_A
        );

        return array_map(function($tag) {
            return [
                'name' => $tag['name'],
                'slug' => $tag['slug'],
                'description' => $tag['description'] ?: '',
                'status' => $tag['status'],
            ];
        }, $tags ?: []);
    }

    /**
     * Export products with all relationships
     *
     * @param array $product_ids Optional specific product IDs
     * @return array Products data
     */
    private function export_products($product_ids = []) {
        global $wpdb;

        // Build query — exclude deleted, and exclude trashed unless option is set
        $excluded = ["'deleted'"];
        if (empty($this->options['include_trashed'])) {
            $excluded[] = "'trash'";
        }
        $where = "WHERE p.status NOT IN (" . implode(',', $excluded) . ")";
        if (!empty($product_ids)) {
            $ids = implode(',', array_map('intval', $product_ids));
            $where .= " AND p.id IN ($ids)";
        }

        $products = $wpdb->get_results(
            "SELECT p.*, tr.name as tax_rate_name
             FROM {$wpdb->prefix}ggmc_products p
             LEFT JOIN {$wpdb->prefix}ggmc_tax_rates tr ON p.tax_rate_id = tr.id
             $where
             ORDER BY p.name",
            ARRAY_A
        );

        if (empty($products)) {
            return [];
        }

        return array_map(function($product) {
            return $this->format_product($product);
        }, $products);
    }

    /**
     * Format a single product for export
     *
     * @param array $product Product data
     * @return array Formatted product
     */
    private function format_product($product) {
        global $wpdb;

        $sku = $product['sku'];

        // Get main image
        $image = $this->get_image_data($product['image_id'], 'products', $sku);

        // Get gallery images
        $gallery_images = [];
        if (!empty($product['gallery_ids'])) {
            $gallery_ids = json_decode($product['gallery_ids'], true);
            if (is_array($gallery_ids)) {
                $i = 1;
                foreach ($gallery_ids as $gallery_id) {
                    $gallery_images[] = $this->get_image_data($gallery_id, 'products', $sku . '/gallery-' . $i);
                    $i++;
                }
            }
        }

        // Get categories
        $categories = $wpdb->get_col($wpdb->prepare(
            "SELECT c.name
             FROM {$wpdb->prefix}ggmc_product_categories pc
             INNER JOIN {$wpdb->prefix}ggmc_categories c ON pc.category_id = c.id
             WHERE pc.product_id = %d",
            $product['id']
        ));

        // Get tags
        $tags = $wpdb->get_col($wpdb->prepare(
            "SELECT t.name
             FROM {$wpdb->prefix}ggmc_product_tags pt
             INNER JOIN {$wpdb->prefix}ggmc_tags t ON pt.tag_id = t.id
             WHERE pt.product_id = %d",
            $product['id']
        ));

        // Get attributes
        $attributes = $this->get_product_attributes($product['id']);

        // Get barcodes
        $barcodes = $this->get_product_barcodes($product['id']);

        // Get downloads
        $downloads = $this->get_product_downloads($product['id']);

        // Get kit components
        $kit_config = null;
        $kit_components = [];
        if ($product['product_type'] === 'kit') {
            $kit_data = $this->get_product_kit($product['id']);
            $kit_config = $kit_data['config'];
            $kit_components = $kit_data['components'];
        }

        // Get variations
        $variations = [];
        $variation_attributes_used = [];
        if ($product['has_variations']) {
            $var_data = $this->get_product_variations($product['id'], $sku);
            $variations = $var_data['variations'];
            $variation_attributes_used = $var_data['attributes_used'];
        }

        $formatted = [
            'sku' => $sku,
            'name' => $product['name'],
            'slug' => $product['slug'],
            'short_description' => $product['short_description'] ?: '',
            'description' => $product['description'] ?: '',
            'price' => $product['price'] !== null ? (float) $product['price'] : null,
            'sale_price' => $product['sale_price'] !== null ? (float) $product['sale_price'] : null,
            'stock' => $product['stock'] !== null ? (int) $product['stock'] : null,
            'stock_status' => $product['stock_status'] ?: 'instock',
            'manage_stock' => (bool) $product['manage_stock'],
            'weight' => $product['weight'] !== null ? (float) $product['weight'] : null,
            'length' => $product['length'] !== null ? (float) $product['length'] : null,
            'width' => $product['width'] !== null ? (float) $product['width'] : null,
            'height' => $product['height'] !== null ? (float) $product['height'] : null,
            'image' => $image,
            'gallery_images' => array_filter($gallery_images),
            'featured' => (bool) $product['featured'],
            'status' => $product['status'],
            'product_type' => $product['product_type'] ?: 'simple',
            'tax_rate' => $product['tax_rate_name'] ?: null,
            'requires_shipping' => (bool) $product['requires_shipping'],
            'is_virtual' => (bool) $product['is_virtual'],
            'is_downloadable' => (bool) $product['is_downloadable'],
            'categories' => $categories ?: [],
            'tags' => $tags ?: [],
            'attributes' => $attributes,
            'barcodes' => $barcodes,
            'downloads' => $downloads,
        ];

        // Add variation data if applicable
        if ($product['has_variations']) {
            $formatted['has_variations'] = true;
            $formatted['variation_mode'] = $product['variation_mode'] ?: 'combined';
            $formatted['variation_stock_mode'] = $product['variation_stock_mode'] ?: 'parent';
            $formatted['variation_attributes_used'] = $variation_attributes_used;
            $formatted['variations'] = $variations;
        }

        // Add kit data if applicable
        if ($product['product_type'] === 'kit') {
            $formatted['kit_config'] = $kit_config;
            $formatted['kit_components'] = $kit_components;
        }

        return $formatted;
    }

    /**
     * Get product attributes
     *
     * @param int $product_id Product ID
     * @return array Attributes as name => value pairs
     */
    private function get_product_attributes($product_id) {
        global $wpdb;

        $attrs = $wpdb->get_results($wpdb->prepare(
            "SELECT a.name, pav.attribute_value
             FROM {$wpdb->prefix}ggmc_product_attribute_values pav
             INNER JOIN {$wpdb->prefix}ggmc_attributes a ON pav.attribute_id = a.id
             WHERE pav.product_id = %d",
            $product_id
        ), ARRAY_A);

        $result = [];
        foreach ($attrs ?: [] as $attr) {
            $result[$attr['name']] = $attr['attribute_value'];
        }

        return $result;
    }

    /**
     * Get product barcodes
     *
     * @param int $product_id Product ID
     * @return array Barcodes
     */
    private function get_product_barcodes($product_id) {
        global $wpdb;

        $barcodes = $wpdb->get_results($wpdb->prepare(
            "SELECT barcode_value, barcode_type, is_primary
             FROM {$wpdb->prefix}ggmc_product_barcodes
             WHERE product_id = %d
             ORDER BY is_primary DESC",
            $product_id
        ), ARRAY_A);

        return array_map(function($bc) {
            return [
                'value' => $bc['barcode_value'],
                'type' => $bc['barcode_type'],
                'is_primary' => (bool) $bc['is_primary'],
            ];
        }, $barcodes ?: []);
    }

    /**
     * Get product downloads
     *
     * @param int $product_id Product ID
     * @return array Downloads
     */
    private function get_product_downloads($product_id) {
        global $wpdb;

        $downloads = $wpdb->get_results($wpdb->prepare(
            "SELECT name, file_url, file_type, file_size, download_limit, access_expiry_days, display_order, status
             FROM {$wpdb->prefix}ggmc_product_downloads
             WHERE product_id = %d AND status = 'active'
             ORDER BY display_order",
            $product_id
        ), ARRAY_A);

        return array_map(function($dl) {
            return [
                'name' => $dl['name'],
                'file_url' => $dl['file_url'],
                'file_type' => $dl['file_type'] ?: '',
                'file_size' => (int) $dl['file_size'],
                'download_limit' => (int) $dl['download_limit'],
                'access_expiry_days' => (int) $dl['access_expiry_days'],
                'display_order' => (int) $dl['display_order'],
            ];
        }, $downloads ?: []);
    }

    /**
     * Get product kit configuration and components
     *
     * @param int $product_id Product ID
     * @return array Kit data with config and components
     */
    private function get_product_kit($product_id) {
        global $wpdb;

        $kit = $wpdb->get_row($wpdb->prepare(
            "SELECT kit_type, auto_calculate_price
             FROM {$wpdb->prefix}ggmc_product_kits
             WHERE product_id = %d",
            $product_id
        ), ARRAY_A);

        $config = null;
        if ($kit) {
            $config = [
                'kit_type' => $kit['kit_type'],
                'auto_calculate_price' => (bool) $kit['auto_calculate_price'],
            ];
        }

        $components = $wpdb->get_results($wpdb->prepare(
            "SELECT p.sku as component_sku, kc.quantity, kc.display_order
             FROM {$wpdb->prefix}ggmc_kit_components kc
             INNER JOIN {$wpdb->prefix}ggmc_product_kits pk ON kc.kit_id = pk.id
             INNER JOIN {$wpdb->prefix}ggmc_products p ON kc.component_product_id = p.id
             WHERE pk.product_id = %d
             ORDER BY kc.display_order",
            $product_id
        ), ARRAY_A);

        return [
            'config' => $config,
            'components' => array_map(function($c) {
                return [
                    'component_sku' => $c['component_sku'],
                    'quantity' => (int) $c['quantity'],
                    'display_order' => (int) $c['display_order'],
                ];
            }, $components ?: []),
        ];
    }

    /**
     * Get product variations
     *
     * @param int $product_id Product ID
     * @param string $parent_sku Parent product SKU
     * @return array Variations data and attributes used
     */
    private function get_product_variations($product_id, $parent_sku) {
        global $wpdb;

        // Get variation types used by this product
        $attrs_used = $wpdb->get_col($wpdb->prepare(
            "SELECT vt.name
             FROM {$wpdb->prefix}ggmc_product_variation_types pvt
             INNER JOIN {$wpdb->prefix}ggmc_variation_types vt ON pvt.variation_type_id = vt.id
             WHERE pvt.product_id = %d
             ORDER BY pvt.display_order",
            $product_id
        ));

        // Get variations
        $variations = $wpdb->get_results($wpdb->prepare(
            "SELECT id, sku, price, sale_price, price_type, stock, stock_status, manage_stock,
                    image_id, gallery_ids, weight, is_default, status
             FROM {$wpdb->prefix}ggmc_product_variations
             WHERE product_id = %d AND status = 'active'
             ORDER BY is_default DESC, sku",
            $product_id
        ), ARRAY_A);

        $formatted_variations = [];
        foreach ($variations ?: [] as $var) {
            // Get variation image
            $var_image = $this->get_image_data($var['image_id'], 'variations', $var['sku'] ?: $parent_sku . '-var-' . $var['id']);

            // Get variation type values
            $var_attrs = $wpdb->get_results($wpdb->prepare(
                "SELECT vt.name, vtv.option_value
                 FROM {$wpdb->prefix}ggmc_variation_type_values vtv
                 INNER JOIN {$wpdb->prefix}ggmc_variation_types vt ON vtv.variation_type_id = vt.id
                 WHERE vtv.variation_id = %d",
                $var['id']
            ), ARRAY_A);

            $attr_map = [];
            foreach ($var_attrs ?: [] as $va) {
                $attr_map[$va['name']] = $va['option_value'];
            }

            $formatted_variations[] = [
                'sku' => $var['sku'] ?: null,
                'price' => $var['price'] !== null ? (float) $var['price'] : null,
                'sale_price' => $var['sale_price'] !== null ? (float) $var['sale_price'] : null,
                'price_type' => $var['price_type'] ?: 'absolute',
                'stock' => $var['stock'] !== null ? (int) $var['stock'] : null,
                'stock_status' => $var['stock_status'] ?: 'instock',
                'manage_stock' => (bool) $var['manage_stock'],
                'image' => $var_image,
                'weight' => $var['weight'] !== null ? (float) $var['weight'] : null,
                'is_default' => (bool) $var['is_default'],
                'status' => $var['status'],
                'attributes' => $attr_map,
            ];
        }

        return [
            'attributes_used' => $attrs_used ?: [],
            'variations' => $formatted_variations,
        ];
    }

    /**
     * Get image data (URL or path for manifest)
     *
     * @param int $image_id WordPress attachment ID
     * @param string $type Image type (products, categories, variations)
     * @param string $identifier SKU or slug for naming
     * @return string|null Image URL or relative path
     */
    private function get_image_data($image_id, $type, $identifier) {
        if (empty($image_id)) {
            return null;
        }

        $url = wp_get_attachment_url($image_id);
        if (!$url) {
            return null;
        }

        if ($this->options['export_image_package']) {
            // Generate path for image package
            $extension = pathinfo($url, PATHINFO_EXTENSION) ?: 'jpg';
            $safe_identifier = sanitize_file_name($identifier);
            $relative_path = "{$type}/{$safe_identifier}.{$extension}";

            // Add to manifest
            $this->image_manifest[] = [
                'path' => $relative_path,
                'original_url' => $url,
                'original_filename' => basename($url),
                'type' => $type,
                'identifier' => $identifier,
                'attachment_id' => $image_id,
            ];

            return $relative_path;
        }

        // Return URL for direct download during import
        return $url;
    }

    /**
     * Export to JSON file
     *
     * @param array $product_ids Optional specific product IDs
     * @return string|WP_Error File path or error
     */
    public function export_to_file($product_ids = []) {
        $data = $this->export($product_ids);

        // Create export directory
        $upload_dir = wp_upload_dir();
        $export_dir = $upload_dir['basedir'] . '/ggm-exports/';
        if (!file_exists($export_dir)) {
            wp_mkdir_p($export_dir);
        }

        // Generate filename
        $timestamp = gmdate('Y-m-d-His');
        $filename = "ggm-export-{$timestamp}.json";
        $filepath = $export_dir . $filename;

        // Write JSON
        $json = wp_json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        if ($json === false) {
            return new WP_Error('json_encode_error', __('Failed to encode export data', 'ggm-commerce'));
        }

        $result = file_put_contents($filepath, $json);
        if ($result === false) {
            return new WP_Error('file_write_error', __('Failed to write export file', 'ggm-commerce'));
        }

        return [
            'file_path' => $filepath,
            'file_url' => $upload_dir['baseurl'] . '/ggm-exports/' . $filename,
            'file_size' => filesize($filepath),
            'counts' => $data['meta']['counts'],
        ];
    }

    /**
     * Export image package to ZIP
     *
     * @return array|WP_Error File info or error
     */
    public function export_image_package() {
        if (empty($this->image_manifest)) {
            return new WP_Error('no_images', __('No images to export. Run export() with export_image_package=true first.', 'ggm-commerce'));
        }

        if (!class_exists('ZipArchive')) {
            return new WP_Error('zip_unavailable', __('ZIP extension not available on this server', 'ggm-commerce'));
        }

        // Create export directory
        $upload_dir = wp_upload_dir();
        $export_dir = $upload_dir['basedir'] . '/ggm-exports/';
        if (!file_exists($export_dir)) {
            wp_mkdir_p($export_dir);
        }

        // Generate filename
        $timestamp = gmdate('Y-m-d-His');
        $filename = "ggm-images-{$timestamp}.zip";
        $filepath = $export_dir . $filename;

        $zip = new ZipArchive();
        if ($zip->open($filepath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
            return new WP_Error('zip_create_error', __('Failed to create ZIP file', 'ggm-commerce'));
        }

        $images_added = 0;
        $errors = [];

        foreach ($this->image_manifest as $image) {
            // Get local file path from attachment ID
            $local_path = get_attached_file($image['attachment_id']);

            if ($local_path && file_exists($local_path)) {
                $zip->addFile($local_path, $image['path']);
                $images_added++;
            } else {
                $errors[] = $image['path'];
            }
        }

        // Add manifest to ZIP
        $manifest_json = wp_json_encode($this->image_manifest, JSON_PRETTY_PRINT);
        $zip->addFromString('manifest.json', $manifest_json);

        $zip->close();

        return [
            'file_path' => $filepath,
            'file_url' => $upload_dir['baseurl'] . '/ggm-exports/' . $filename,
            'file_size' => filesize($filepath),
            'images_added' => $images_added,
            'images_failed' => count($errors),
            'errors' => $errors,
        ];
    }

    /**
     * Get the image manifest (for use after export)
     *
     * @return array Image manifest
     */
    public function get_image_manifest() {
        return $this->image_manifest;
    }
}
