<?php
/**
 * Product Sync Component for Magento Integration
 *
 * @category    PortalPeople
 * @package     Magento
 * @author      Portal People Development Team
 * @copyright   Copyright (c) 2025 Portal People (https://portalpeople.co.uk)
 */

namespace PortalPeople\magento\components;

use Yii;
use yii\base\Component;
use yii\base\InvalidConfigException;
use yii\db\ActiveRecord;
use yii\queue\Queue;

/**
 * Product Sync Component
 * 
 * Handles synchronization of product data between local system and Magento
 */
class ProductSyncComponent extends Component
{
    /**
     * @var array Price fields to monitor for changes
     */
    public $priceFields = ['price1', 'price2', 'price3'];

    /**
     * @var bool Enable debug mode
     */
    public $debug = false;

    /**
     * @var bool Enable queue for async processing
     */
    public $useQueue = true;

    /**
     * @var string Queue component name
     */
    public $queueComponent = 'queue';

    /**
     * @var array Mapping of local product fields to Magento fields
     */
    public $fieldMapping = [
        'sku' => 'sku',
        'name' => 'name',
        'price1' => 'price',
        'price2' => 'special_price',
        'description' => 'description',
        'short_description' => 'short_description',
        'weight' => 'weight',
        'status' => 'status'
    ];

    /**
     * @var MagentoClient
     */
    private $magentoClient;

    /**
     * @inheritdoc
     */
    public function init()
    {
        parent::init();

        $this->magentoClient = Yii::$app->magentoClient;
        
        if (!$this->magentoClient) {
            throw new InvalidConfigException('MagentoClient component is not configured');
        }
    }

    /**
     * Sync product to Magento
     * 
     * @param ActiveRecord $product
     * @param string $action (create|update|delete)
     * @return bool
     */
    public function syncProduct($product, $action = 'update')
    {
        try {
            $this->log("Starting product sync: SKU {$product->sku}, Action: {$action}");

            if ($this->useQueue && Yii::$app->has($this->queueComponent)) {
                // Queue the sync job for async processing
                $job = new \PortalPeople\magento\jobs\ProductSyncJob([
                    'productId' => $product->id,
                    'productData' => $this->extractProductData($product),
                    'action' => $action
                ]);

                Yii::$app->get($this->queueComponent)->push($job);
                $this->log("Product sync job queued for SKU: {$product->sku}");
                return true;
            } else {
                // Process sync immediately
                return $this->processSyncJob($product, $action);
            }

        } catch (\Exception $e) {
            $this->log("Error syncing product {$product->sku}: " . $e->getMessage(), 'error');
            return false;
        }
    }

    /**
     * Process sync job immediately
     * 
     * @param ActiveRecord $product
     * @param string $action
     * @return bool
     */
    public function processSyncJob($product, $action)
    {
        try {
            $productData = $this->extractProductData($product);

            switch ($action) {
                case 'create':
                    return $this->createProduct($productData);
                
                case 'update':
                    return $this->updateProduct($productData);
                
                case 'delete':
                    return $this->deleteProduct($product->sku);
                
                default:
                    throw new \InvalidArgumentException("Unknown sync action: {$action}");
            }

        } catch (\Exception $e) {
            $this->log("Error processing sync job: " . $e->getMessage(), 'error');
            return false;
        }
    }

    /**
     * Create product in Magento
     * 
     * @param array $productData
     * @return bool
     */
    protected function createProduct($productData)
    {
        try {
            // Check if product already exists
            $existingProduct = $this->magentoClient->getProduct($productData['sku']);
            
            if ($existingProduct) {
                $this->log("Product {$productData['sku']} already exists, updating instead");
                return $this->updateProduct($productData);
            }

            // Set required fields for creation
            $productData = array_merge($productData, [
                'type_id' => 'simple',
                'attribute_set_id' => 4, // Default attribute set
                'visibility' => 4, // Catalog, Search
                'status' => 1 // Enabled
            ]);

            $result = $this->magentoClient->createProduct($productData);
            
            $this->log("Successfully created product in Magento: {$productData['sku']}");
            return true;

        } catch (\Exception $e) {
            $this->log("Error creating product in Magento: " . $e->getMessage(), 'error');
            return false;
        }
    }

    /**
     * Update product in Magento
     * 
     * @param array $productData
     * @return bool
     */
    protected function updateProduct($productData)
    {
        try {
            $sku = $productData['sku'];
            
            // Remove fields that shouldn't be updated
            unset($productData['type_id'], $productData['attribute_set_id']);

            $result = $this->magentoClient->updateProduct($sku, $productData);
            
            $this->log("Successfully updated product in Magento: {$sku}");
            return true;

        } catch (\Exception $e) {
            $this->log("Error updating product in Magento: " . $e->getMessage(), 'error');
            return false;
        }
    }

    /**
     * Delete product in Magento
     * 
     * @param string $sku
     * @return bool
     */
    protected function deleteProduct($sku)
    {
        try {
            // Magento doesn't have a direct delete API, so we disable the product
            $result = $this->magentoClient->updateProduct($sku, ['status' => 2]); // Disabled
            
            $this->log("Successfully disabled product in Magento: {$sku}");
            return true;

        } catch (\Exception $e) {
            $this->log("Error disabling product in Magento: " . $e->getMessage(), 'error');
            return false;
        }
    }

    /**
     * Sync only price changes
     * 
     * @param ActiveRecord $product
     * @param array $changedFields
     * @return bool
     */
    public function syncPriceChanges($product, $changedFields = [])
    {
        try {
            $priceChanges = array_intersect($changedFields, $this->priceFields);
            
            if (empty($priceChanges)) {
                return true; // No price changes to sync
            }

            $this->log("Syncing price changes for SKU {$product->sku}: " . implode(', ', $priceChanges));

            $priceData = [];
            foreach ($priceChanges as $field) {
                if (isset($this->fieldMapping[$field])) {
                    $magentoField = $this->fieldMapping[$field];
                    $priceData[$magentoField] = $product->$field;
                }
            }

            if (!empty($priceData)) {
                $result = $this->magentoClient->updateProduct($product->sku, $priceData);
                $this->log("Successfully synced price changes for SKU: {$product->sku}");
                return true;
            }

            return true;

        } catch (\Exception $e) {
            $this->log("Error syncing price changes for {$product->sku}: " . $e->getMessage(), 'error');
            return false;
        }
    }

    /**
     * Extract product data for Magento sync
     * 
     * @param ActiveRecord $product
     * @return array
     */
    protected function extractProductData($product)
    {
        $data = [];

        foreach ($this->fieldMapping as $localField => $magentoField) {
            if ($product->hasAttribute($localField) && $product->$localField !== null) {
                $data[$magentoField] = $product->$localField;
            }
        }

        // Ensure SKU is always included
        if (!isset($data['sku']) && $product->hasAttribute('sku')) {
            $data['sku'] = $product->sku;
        }

        // Set default values if missing
        if (!isset($data['name']) && isset($data['sku'])) {
            $data['name'] = $data['sku']; // Use SKU as name fallback
        }

        return $data;
    }

    /**
     * Bulk sync products
     * 
     * @param array $products
     * @param string $action
     * @return array Results array with success/failure counts
     */
    public function bulkSync($products, $action = 'update')
    {
        $results = [
            'total' => count($products),
            'success' => 0,
            'failed' => 0,
            'errors' => []
        ];

        foreach ($products as $product) {
            try {
                if ($this->syncProduct($product, $action)) {
                    $results['success']++;
                } else {
                    $results['failed']++;
                    $results['errors'][] = "Failed to sync product: {$product->sku}";
                }
            } catch (\Exception $e) {
                $results['failed']++;
                $results['errors'][] = "Error syncing {$product->sku}: " . $e->getMessage();
            }
        }

        $this->log("Bulk sync completed: {$results['success']} success, {$results['failed']} failed");

        return $results;
    }

    /**
     * Test sync connection
     * 
     * @return bool
     */
    public function testConnection()
    {
        return $this->magentoClient->testConnection();
    }

    /**
     * Get sync statistics
     * 
     * @return array
     */
    public function getStats()
    {
        // This would typically query a sync log table
        return [
            'last_sync' => null,
            'total_synced' => 0,
            'success_rate' => 0,
            'is_connected' => $this->testConnection()
        ];
    }

    /**
     * Synchronize product by SKU
     * 
     * @param string $sku Product SKU
     * @return bool Success status
     */
    public function syncProductBySku($sku)
    {
        try {
            // Find product by SKU (you'll need to implement this based on your model)
            // This is a placeholder implementation
            
            /*
            $product = Product::findOne(['sku' => $sku]);
            if (!$product) {
                Yii::error("Product not found: $sku");
                return false;
            }

            // Get price data
            $priceData = [];
            $priceFields = $this->getModule()->priceFields ?? ['price1', 'price2', 'price3'];
            
            foreach ($priceFields as $field) {
                if (isset($product->$field)) {
                    $priceData[$field] = $product->$field;
                }
            }

            return $this->syncProduct($sku, $priceData);
            */

            // For now, just log the attempt
            Yii::info("Console sync attempted for product: $sku");
            return true;

        } catch (\Exception $e) {
            Yii::error('Product sync by SKU failed: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * Log message
     * 
     * @param string $message
     * @param string $level
     */
    protected function log($message, $level = 'info')
    {
        if ($this->debug) {
            Yii::getLogger()->log($message, \yii\log\Logger::LEVEL_INFO, 'magento-sync');
        }

        if ($level === 'error') {
            Yii::error($message, 'magento-sync');
        }
    }
}