<?php
/**
 * Live Feed Sync Service - Handles synchronization of products from remote feeds.
 *
 * @package PrimeLink
 */

namespace PrimeLink\Modules\LiveFeed;

use PrimeLink\Modules\Imports\Service\ImportRunner;
use PrimeLink\Helpers\LoggerHelper;

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

final class LiveFeedSyncService {

    /**
     * Sync a feed manually or automatically.
     * Can be called as WordPress action hook.
     *
     * @param string $feed_id Feed ID.
     * @return array Sync result.
     */
    public static function sync_feed( $feed_id = '' ) {
        // If called as action hook, feed_id is first argument
        if ( empty( $feed_id ) && func_num_args() > 0 ) {
            $feed_id = func_get_arg( 0 );
        }
        $feed = LiveFeedService::get_feed( $feed_id );
        if ( ! $feed ) {
            return array(
                'success' => false,
                'message' => 'Feed not found.',
            );
        }

        if ( $feed['status'] !== 'active' ) {
            return array(
                'success' => false,
                'message' => 'Feed is not active.',
            );
        }

        try {
            // Fetch products from source
            $products = self::fetch_products_from_source( $feed );
            
            if ( empty( $products ) ) {
                return array(
                    'success' => true,
                    'message' => 'No products to sync.',
                    'synced'  => 0,
                );
            }

            // Sync products
            $result = self::sync_products( $feed, $products );

            // Update feed stats
            LiveFeedService::update_feed_stats( $feed_id, array(
                'total_syncs'    => $feed['stats']['total_syncs'] + 1,
                'total_products' => $feed['stats']['total_products'] + $result['synced'],
                'last_error'     => null,
            ) );

            return array(
                'success' => true,
                'message' => sprintf( 'Synced %d products.', $result['synced'] ),
                'synced'  => $result['synced'],
                'updated' => $result['updated'],
                'created' => $result['created'],
                'errors'  => $result['errors'],
            );

        } catch ( \Throwable $e ) {
            LoggerHelper::error( 'Live Feed sync error: ' . $e->getMessage(), array( 'feed_id' => $feed_id ) );
            
            LiveFeedService::update_feed_stats( $feed_id, array(
                'last_error' => $e->getMessage(),
            ) );

            return array(
                'success' => false,
                'message' => $e->getMessage(),
            );
        }
    }

    /**
     * Fetch products from source URL.
     *
     * @param array $feed Feed data.
     * @return array Products.
     */
    private static function fetch_products_from_source( $feed ) {
        $source_type = $feed['source_type'] ?? 'prime_woocommerce';

        /**
         * Mode 1: PrimeLink ↔ PrimeLink (default, backwards compatible).
         * Calls the remote PrimeLink Live Feed endpoint with X-API-Key.
         */
        if ( $source_type === 'prime_woocommerce' ) {
            $url = trailingslashit( $feed['source_url'] ) . 'wp-json/mt-primelink/v1/live-feed/products';

            $args = array(
                'headers' => array(
                    'X-API-Key' => $feed['api_key'],
                ),
                'timeout' => 30,
            );

            // Add modified_since if last sync exists
            if ( ! empty( $feed['last_sync'] ) ) {
                $url = add_query_arg( 'modified_since', $feed['last_sync'], $url );
            }

            $response = wp_remote_get( $url, $args );
        } elseif ( $source_type === 'woocommerce_rest' ) {
            /**
             * Mode 2: WooCommerce REST API (no PrimeLink on source).
             * Uses WooCommerce consumer key/secret generated on the supplier store.
             */
            $base_url = trailingslashit( $feed['source_url'] ) . 'wp-json/wc/v3/products';

            $query_args = array(
                'per_page' => 100,
                'status'   => 'publish',
            );

            $consumer_key    = $feed['wc_consumer_key'] ?? '';
            $consumer_secret = $feed['wc_consumer_secret'] ?? '';

            if ( empty( $consumer_key ) || empty( $consumer_secret ) ) {
                throw new \Exception( 'WooCommerce REST credentials are missing for this feed.' );
            }

            // Basic Auth is the most compatible, WooCommerce also supports query args.
            $args = array(
                'headers' => array(
                    'Authorization' => 'Basic ' . base64_encode( $consumer_key . ':' . $consumer_secret ),
                ),
                'timeout' => 30,
            );

            // Paginate through products to support more than 100 items.
            $all_products = array();
            $page         = 1;
            $max_pages    = 10; // Safety cap: up to 1000 products per sync.

            do {
                $query_args['page'] = $page;
                $url                = add_query_arg( $query_args, $base_url );
                $response           = wp_remote_get( $url, $args );

                if ( is_wp_error( $response ) ) {
                    throw new \Exception( 'Failed to fetch products (page ' . $page . '): ' . $response->get_error_message() );
                }

                $body = wp_remote_retrieve_body( $response );
                $data = json_decode( $body, true );

                if ( ! is_array( $data ) || empty( $data ) ) {
                    break;
                }

                $all_products = array_merge( $all_products, $data );
                $count        = count( $data );
                $page++;

                // Continue while we get full pages and haven't hit the safety cap.
            } while ( $count === $query_args['per_page'] && $page <= $max_pages );

            return $all_products;
        } else {
            // Unsupported / future source type.
            throw new \Exception( 'Unsupported live feed source type: ' . $source_type );
        }

        if ( is_wp_error( $response ) ) {
            throw new \Exception( 'Failed to fetch products: ' . $response->get_error_message() );
        }

        $body = wp_remote_retrieve_body( $response );
        $data = json_decode( $body, true );

        if ( $source_type === 'prime_woocommerce' ) {
            if ( ! isset( $data['products'] ) ) {
                throw new \Exception( 'Invalid response from PrimeLink source.' );
            }

            return $data['products'];
        }

        // Fallback (should not be reached due to earlier guard).
        throw new \Exception( 'Unhandled live feed source type.' );
    }

    /**
     * Sync products to local store.
     *
     * @param array $feed Feed data.
     * @param array $products Products from source.
     * @return array Sync result.
     */
    private static function sync_products( $feed, $products ) {
        $synced = 0;
        $updated = 0;
        $created = 0;
        $errors = 0;
        $sync_fields = LiveFeedService::get_sync_fields( $feed );

        foreach ( $products as $product_data ) {
            try {
                // Find existing product by SKU
                $existing_id = 0;
                if ( ! empty( $product_data['sku'] ) ) {
                    $existing_id = wc_get_product_id_by_sku( $product_data['sku'] );
                }

                // Map product data
                $mapped = self::map_product_data( $product_data );

                if ( $existing_id > 0 ) {
                    // Update existing product using ImportRunner's private method via reflection
                    // Or use a public wrapper - for now, we'll use wp_update_post and update meta directly
                    $product = wc_get_product( $existing_id );
                    if ( $product ) {
                        self::update_product_direct( $existing_id, $mapped, $sync_fields );
                        $updated++;
                    } else {
                        $errors++;
                        continue;
                    }
                } else {
                    // Create new product (for new products we always apply full mapped data)
                    $new_id = self::create_product_direct( $mapped, $sync_fields );
                    if ( $new_id > 0 ) {
                        $created++;
                    } else {
                        $errors++;
                        continue;
                    }
                }

                $synced++;

            } catch ( \Exception $e ) {
                LoggerHelper::error( 'Error syncing product: ' . $e->getMessage(), array( 'product' => $product_data ) );
                $errors++;
            }
        }

        return array(
            'synced'  => $synced,
            'updated' => $updated,
            'created' => $created,
            'errors'  => $errors,
        );
    }

    /**
     * Create product directly.
     *
     * @param array $mapped      Mapped product data.
     * @param array $sync_fields Fields to synchronize.
     */
    private static function create_product_direct( $mapped, $sync_fields ) {
        $post_data = array(
            'post_type'    => 'product',
            'post_title'   => $mapped['post']['post_title'] ?? '',
            'post_content' => $mapped['post']['post_content'] ?? '',
            'post_excerpt' => $mapped['post']['post_excerpt'] ?? '',
            'post_status'  => 'publish',
        );

        $product_id = wp_insert_post( $post_data, true );
        if ( is_wp_error( $product_id ) ) {
            return 0;
        }

        self::apply_product_data_direct( $product_id, $mapped, $sync_fields );
        return absint( $product_id );
    }

    /**
     * Update product directly.
     *
     * @param int   $product_id  Product ID.
     * @param array $mapped      Mapped product data.
     * @param array $sync_fields Fields to synchronize.
     */
    private static function update_product_direct( $product_id, $mapped, $sync_fields ) {
        // Update post content only if description sync is enabled.
        if ( in_array( 'description', $sync_fields, true ) ) {
            $post_data = array(
                'ID'           => $product_id,
                'post_title'   => $mapped['post']['post_title'] ?? '',
                'post_content' => $mapped['post']['post_content'] ?? '',
                'post_excerpt' => $mapped['post']['post_excerpt'] ?? '',
            );
            wp_update_post( $post_data );
        }
        self::apply_product_data_direct( $product_id, $mapped, $sync_fields );
    }

    /**
     * Apply product data (meta, taxonomies, images).
     *
     * @param int   $product_id  Product ID.
     * @param array $mapped      Mapped product data.
     * @param array $sync_fields Fields to synchronize.
     */
    private static function apply_product_data_direct( $product_id, $mapped, $sync_fields ) {
        $product = wc_get_product( $product_id );
        if ( ! $product ) {
            return;
        }

        // Product meta
        if ( isset( $mapped['product']['sku'] ) ) {
            $product->set_sku( $mapped['product']['sku'] );
        }
        if ( in_array( 'price', $sync_fields, true ) ) {
            if ( isset( $mapped['product']['regular_price'] ) ) {
                $product->set_regular_price( $mapped['product']['regular_price'] );
            }
            if ( isset( $mapped['product']['sale_price'] ) ) {
                $product->set_sale_price( $mapped['product']['sale_price'] );
            }
        }
        if ( in_array( 'stock', $sync_fields, true ) ) {
            if ( isset( $mapped['product']['stock'] ) ) {
                $product->set_stock_quantity( $mapped['product']['stock'] );
            }
            if ( isset( $mapped['product']['stock_status'] ) ) {
                $product->set_stock_status( $mapped['product']['stock_status'] );
            }
        }
        // Dimensions are usually safe to sync with price/stock; keep them unconditional for now.
        if ( isset( $mapped['product']['weight'] ) ) {
            $product->set_weight( $mapped['product']['weight'] );
        }
        if ( isset( $mapped['product']['length'] ) ) {
            $product->set_length( $mapped['product']['length'] );
        }
        if ( isset( $mapped['product']['width'] ) ) {
            $product->set_width( $mapped['product']['width'] );
        }
        if ( isset( $mapped['product']['height'] ) ) {
            $product->set_height( $mapped['product']['height'] );
        }
        $product->save();

        // Taxonomies
        if ( in_array( 'categories', $sync_fields, true ) && ! empty( $mapped['tax']['product_cat'] ) ) {
            wp_set_object_terms( $product_id, $mapped['tax']['product_cat'], 'product_cat' );
        }
        if ( in_array( 'tags', $sync_fields, true ) && ! empty( $mapped['tax']['product_tag'] ) ) {
            wp_set_object_terms( $product_id, $mapped['tax']['product_tag'], 'product_tag' );
        }

        // Images
        if ( in_array( 'images', $sync_fields, true ) && ! empty( $mapped['images'] ) && is_array( $mapped['images'] ) ) {
            $image_ids = array();
            foreach ( $mapped['images'] as $image_url ) {
                $attachment_id = self::import_image_from_url( $image_url, $product_id );
                if ( $attachment_id ) {
                    $image_ids[] = $attachment_id;
                }
            }
            if ( ! empty( $image_ids ) ) {
                $product->set_image_id( $image_ids[0] );
                if ( count( $image_ids ) > 1 ) {
                    $product->set_gallery_image_ids( array_slice( $image_ids, 1 ) );
                }
                $product->save();
            }
        }
    }

    /**
     * Import image from URL.
     */
    private static function import_image_from_url( $url, $parent_id = 0 ) {
        require_once ABSPATH . 'wp-admin/includes/media.php';
        require_once ABSPATH . 'wp-admin/includes/file.php';
        require_once ABSPATH . 'wp-admin/includes/image.php';

        $tmp = download_url( $url );
        if ( is_wp_error( $tmp ) ) {
            return 0;
        }

        $file_array = array(
            'name'     => basename( $url ),
            'tmp_name' => $tmp,
        );

        $id = media_handle_sideload( $file_array, $parent_id );
        if ( is_wp_error( $id ) ) {
            @unlink( $tmp );
            return 0;
        }

        return $id;
    }

    /**
     * Map product data from feed format to import format.
     *
     * @param array $product_data Product data from feed.
     * @return array Mapped product data.
     */
    private static function map_product_data( $product_data ) {
        // Normalize categories from WooCommerce REST (array of objects) or generic arrays.
        $categories = $product_data['categories'] ?? array();
        if ( is_array( $categories ) ) {
            $normalized_cats = array();
            foreach ( $categories as $cat ) {
                if ( is_array( $cat ) ) {
                    // WooCommerce REST: ['id' => 1, 'name' => 'Category', 'slug' => 'category']
                    $label = $cat['name'] ?? $cat['slug'] ?? '';
                    if ( $label !== '' ) {
                        $normalized_cats[] = $label;
                    }
                } elseif ( is_scalar( $cat ) ) {
                    $label = trim( (string) $cat );
                    if ( $label !== '' ) {
                        $normalized_cats[] = $label;
                    }
                }
            }
            $categories = $normalized_cats;
        } else {
            $categories = array();
        }

        // Normalize tags from WooCommerce REST (array of objects) or generic arrays.
        $tags = $product_data['tags'] ?? array();
        if ( is_array( $tags ) ) {
            $normalized_tags = array();
            foreach ( $tags as $tag ) {
                if ( is_array( $tag ) ) {
                    $label = $tag['name'] ?? $tag['slug'] ?? '';
                    if ( $label !== '' ) {
                        $normalized_tags[] = $label;
                    }
                } elseif ( is_scalar( $tag ) ) {
                    $label = trim( (string) $tag );
                    if ( $label !== '' ) {
                        $normalized_tags[] = $label;
                    }
                }
            }
            $tags = $normalized_tags;
        } else {
            $tags = array();
        }

        // Normalize images from WooCommerce REST (array of objects with 'src').
        $images = $product_data['images'] ?? array();
        if ( is_array( $images ) ) {
            $normalized_images = array();
            foreach ( $images as $img ) {
                if ( is_array( $img ) && ! empty( $img['src'] ) ) {
                    $normalized_images[] = $img['src'];
                } elseif ( is_scalar( $img ) ) {
                    $url = trim( (string) $img );
                    if ( $url !== '' ) {
                        $normalized_images[] = $url;
                    }
                }
            }
            $images = $normalized_images;
        } else {
            $images = array();
        }

        $mapped = array(
            'post' => array(
                'post_title'   => $product_data['name'] ?? '',
                'post_content' => $product_data['description'] ?? '',
                'post_excerpt' => $product_data['short_description'] ?? '',
            ),
            'product' => array(
                'sku'            => $product_data['sku'] ?? '',
                'regular_price' => $product_data['price'] ?? '',
                'sale_price'    => $product_data['sale_price'] ?? '',
                'stock'         => $product_data['stock_quantity'] ?? '',
                'stock_status'  => $product_data['stock_status'] ?? 'instock',
                'weight'        => $product_data['weight'] ?? '',
                'length'        => $product_data['length'] ?? '',
                'width'         => $product_data['width'] ?? '',
                'height'        => $product_data['height'] ?? '',
            ),
            'tax' => array(
                'product_cat' => $categories,
                'product_tag' => $tags,
            ),
            'images' => $images,
        );

        return $mapped;
    }

    /**
     * Schedule automatic sync for a feed.
     *
     * @param string $feed_id Feed ID.
     * @return bool Success.
     */
    public static function schedule_sync( $feed_id ) {
        $feed = LiveFeedService::get_feed( $feed_id );
        if ( ! $feed || $feed['sync_mode'] !== 'auto' ) {
            return false;
        }

        $hook = 'mt_primelink_live_feed_sync';
        $args = array( $feed_id );

        // Clear existing schedule
        wp_clear_scheduled_hook( $hook, $args );

        // Schedule new sync
        $interval = $feed['interval'] ?? 300; // Default 5 minutes
        wp_schedule_event( time() + $interval, 'mt_primelink_live_feed_interval', $hook, $args );

        return true;
    }

    /**
     * Register custom cron interval.
     */
    public static function register_cron_intervals() {
        add_filter( 'cron_schedules', function( $schedules ) {
            $schedules['mt_primelink_live_feed_interval'] = array(
                'interval' => 60, // 1 minute (will be adjusted per feed)
                'display'  => __( 'PrimeLink Live Feed Interval', 'primelink' ),
            );
            return $schedules;
        } );
    }
}

