<?php
/**
 * Dynamic Field Mapper 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\helpers\ArrayHelper;
use backend\models\Productsbe;
use PortalPeople\magento\components\MagentoClient;

/**
 * Dynamic Field Mapper Component
 * 
 * Maps fields between NGauge Productsbe model and Magento product attributes
 */
class FieldMapper extends Component
{
    /**
     * @var MagentoClient Magento API client
     */
    protected $magentoClient;

    /**
     * @var array Cached NGauge fields
     */
    protected $ngaugeFields;

    /**
     * @var array Cached Magento fields
     */
    protected $magentoFields;

    /**
     * @var int Cache duration in seconds (default: 1 hour)
     */
    protected $cacheDuration = 3600;

    /**
     * @var string Cache key prefix
     */
    protected $cacheKeyPrefix = 'magento.field_mapper';

    /**
     * @inheritdoc
     */
    public function init()
    {
        parent::init();
        
        // Initialize Magento client if available
        $config = Yii::$app->params['plugins']['magento'] ?? [];
        if (!empty($config) && ($config['enabled'] ?? false)) {
            $clientConfig = array_intersect_key($config, array_flip([
                'apiUrl', 'accessToken', 'adminUsername', 'adminPassword', 
                'storeCode', 'timeout', 'debug'
            ]));
            
            try {
                $this->magentoClient = new MagentoClient($clientConfig);
            } catch (\Exception $e) {
                Yii::warning('Failed to initialize Magento client: ' . $e->getMessage());
            }
        }
    }

    /**
     * Get NGauge product fields from Productsbe model
     * 
     * @return array
     */
    public function getNGaugeFields()
    {
        if ($this->ngaugeFields === null) {
            // Try to get from cache first
            $cacheKey = $this->cacheKeyPrefix . '.ngauge_fields';
            $cachedFields = Yii::$app->cache ? Yii::$app->cache->get($cacheKey) : false;
            
            if ($cachedFields !== false) {
                $this->ngaugeFields = $cachedFields;
                if (YII_ENV_DEV) {
                    Yii::info('NGauge fields loaded from cache', 'magento.field_mapping');
                }
            } else {
                // Generate fields from Productsbe model
                $model = new Productsbe();
                $attributes = $model->attributes();
                $labels = $model->attributeLabels();
                
                $this->ngaugeFields = [];
                
                foreach ($attributes as $attribute) {
                    $this->ngaugeFields[$attribute] = [
                        'code' => $attribute,
                        'label' => $labels[$attribute] ?? ucfirst(str_replace('_', ' ', $attribute)),
                        'type' => $this->detectNGaugeFieldType($attribute),
                        'category' => $this->categorizeNGaugeField($attribute)
                    ];
                }
                
                // Sort by category then by label
                uasort($this->ngaugeFields, function($a, $b) {
                    $categoryOrder = ['identification' => 1, 'basic' => 2, 'pricing' => 3, 'content' => 4, 'stock' => 5, 'system' => 6];
                    $aCat = $categoryOrder[$a['category']] ?? 99;
                    $bCat = $categoryOrder[$b['category']] ?? 99;
                    
                    if ($aCat !== $bCat) {
                        return $aCat <=> $bCat;
                    }
                    
                    return strcmp($a['label'], $b['label']);
                });
                
                // Store in cache
                if (Yii::$app->cache) {
                    Yii::$app->cache->set($cacheKey, $this->ngaugeFields, $this->cacheDuration);
                    if (YII_ENV_DEV) {
                        Yii::info('NGauge fields cached for ' . $this->cacheDuration . ' seconds', 'magento.field_mapping');
                    }
                }
            }
        }
        
        return $this->ngaugeFields;
    }

    /**
     * Get Magento product fields
     * 
     * @return array
     */
    public function getMagentoFields()
    {
        if ($this->magentoFields === null) {
            // Try to get from cache first
            $cacheKey = $this->cacheKeyPrefix . '.magento_fields';
            $cachedFields = Yii::$app->cache ? Yii::$app->cache->get($cacheKey) : false;
            
            if ($cachedFields !== false) {
                $this->magentoFields = $cachedFields;
                if (YII_ENV_DEV) {
                    Yii::info('Magento fields loaded from cache', 'magento.field_mapping');
                }
            } else {
                // Fetch fields from Magento API or use defaults
                if ($this->magentoClient) {
                    try {
                        $this->magentoFields = $this->magentoClient->getAvailableProductFields();
                        if (YII_ENV_DEV) {
                            Yii::info('Magento fields fetched from API', 'magento.field_mapping');
                        }
                    } catch (\Exception $e) {
                        Yii::warning('Failed to get Magento fields: ' . $e->getMessage());
                        $this->magentoFields = $this->getDefaultMagentoFields();
                        if (YII_ENV_DEV) {
                            Yii::info('Using default Magento fields due to API error', 'magento.field_mapping');
                        }
                    }
                } else {
                    $this->magentoFields = $this->getDefaultMagentoFields();
                    if (YII_ENV_DEV) {
                        Yii::info('Using default Magento fields (no client available)', 'magento.field_mapping');
                    }
                }
                
                // Store in cache
                if (Yii::$app->cache) {
                    Yii::$app->cache->set($cacheKey, $this->magentoFields, $this->cacheDuration);
                    if (YII_ENV_DEV) {
                        Yii::info('Magento fields cached for ' . $this->cacheDuration . ' seconds', 'magento.field_mapping');
                    }
                }
            }
        }
        
        return $this->magentoFields;
    }

    /**
     * Get categorized NGauge fields
     * 
     * @return array
     */
    public function getCategorizedNGaugeFields()
    {
        $fields = $this->getNGaugeFields();
        $categories = [];
        
        foreach ($fields as $code => $field) {
            $category = $field['category'];
            
            if (!isset($categories[$category])) {
                $categories[$category] = [
                    'label' => $this->getCategoryLabel($category),
                    'fields' => []
                ];
            }
            
            $categories[$category]['fields'][$code] = $field;
        }
        
        return $categories;
    }

    /**
     * Get categorized Magento fields
     * 
     * @return array
     */
    public function getCategorizedMagentoFields()
    {
        if ($this->magentoClient) {
            try {
                return $this->magentoClient->getCategorizedProductFields();
            } catch (\Exception $e) {
                Yii::warning('Failed to get categorized Magento fields: ' . $e->getMessage());
            }
        }
        
        return $this->getDefaultCategorizedMagentoFields();
    }

    /**
     * Clear field mapping cache
     * 
     * @param string|null $type 'ngauge', 'magento', or null for both
     * @return bool
     */
    public function clearCache($type = null)
    {
        if (!Yii::$app->cache) {
            return false;
        }
        
        $success = true;
        
        if ($type === null || $type === 'ngauge') {
            $cacheKey = $this->cacheKeyPrefix . '.ngauge_fields';
            $success = $success && Yii::$app->cache->delete($cacheKey);
            $this->ngaugeFields = null;
        }
        
        if ($type === null || $type === 'magento') {
            $cacheKey = $this->cacheKeyPrefix . '.magento_fields';
            $success = $success && Yii::$app->cache->delete($cacheKey);
            $this->magentoFields = null;
        }
        
        if (YII_ENV_DEV) {
            $typeStr = $type ?: 'all';
            Yii::info("Field mapping cache cleared: {$typeStr}", 'magento.field_mapping');
        }
        
        return $success;
    }

    /**
     * Refresh field mapping cache
     * 
     * @param string|null $type 'ngauge', 'magento', or null for both
     * @return bool
     */
    public function refreshCache($type = null)
    {
        // Clear existing cache
        $this->clearCache($type);
        
        // Reload data (which will rebuild cache)
        if ($type === null || $type === 'ngauge') {
            $this->getNGaugeFields();
        }
        
        if ($type === null || $type === 'magento') {
            $this->getMagentoFields();
        }
        
        return true;
    }

    /**
     * Get cache statistics
     * 
     * @return array
     */
    public function getCacheStats()
    {
        $stats = [
            'cache_enabled' => Yii::$app->cache ? true : false,
            'cache_duration' => $this->cacheDuration,
            'ngauge_cached' => false,
            'magento_cached' => false,
            'ngauge_cache_key' => $this->cacheKeyPrefix . '.ngauge_fields',
            'magento_cache_key' => $this->cacheKeyPrefix . '.magento_fields'
        ];
        
        if (Yii::$app->cache) {
            $stats['ngauge_cached'] = Yii::$app->cache->exists($this->cacheKeyPrefix . '.ngauge_fields');
            $stats['magento_cached'] = Yii::$app->cache->exists($this->cacheKeyPrefix . '.magento_fields');
        }
        
        return $stats;
    }

    /**
     * Generate intelligent field mapping suggestions
     * 
     * @return array
     */
    public function getSuggestedMappings()
    {
        $ngaugeFields = $this->getNGaugeFields();
        $magentoFields = $this->getMagentoFields();
        $suggestions = [];
        
        // Define mapping rules based on field names and types
        $mappingRules = [
            // Direct matches
            'stock_code' => 'sku',
            'product_name' => 'name',
            'product_description' => 'description',
            'product_short_description' => 'short_description',
            'weight' => 'weight',
            'status' => 'status',
            'url' => 'url_key',
            
            // Price mappings
            'price1' => 'price',
            'dmprice' => 'price',
            'price2' => 'special_price',
            
            // Pattern matches
            '/^price\d+$/' => 'price', // price1, price2, etc. -> price
            '/description/' => 'description',
            '/name/' => 'name',
            '/code/' => 'sku',
        ];
        
        foreach ($ngaugeFields as $ngaugeCode => $ngaugeField) {
            $suggestion = null;
            $confidence = 0;
            
            // Check direct mappings first
            foreach ($mappingRules as $pattern => $magentoField) {
                if (strpos($pattern, '/') === 0) {
                    // Regex pattern
                    if (preg_match($pattern, $ngaugeCode) && isset($magentoFields[$magentoField])) {
                        $suggestion = $magentoField;
                        $confidence = 70;
                        break;
                    }
                } else {
                    // Direct match
                    if ($ngaugeCode === $pattern && isset($magentoFields[$magentoField])) {
                        $suggestion = $magentoField;
                        $confidence = 100;
                        break;
                    }
                }
            }
            
            // Fuzzy matching based on similarity
            if (!$suggestion) {
                $bestMatch = null;
                $bestScore = 0;
                
                foreach ($magentoFields as $magentoCode => $magentoField) {
                    $score = $this->calculateFieldSimilarity($ngaugeField, $magentoField);
                    
                    if ($score > $bestScore && $score > 50) {
                        $bestScore = $score;
                        $bestMatch = $magentoCode;
                    }
                }
                
                if ($bestMatch) {
                    $suggestion = $bestMatch;
                    $confidence = $bestScore;
                }
            }
            
            if ($suggestion) {
                $suggestions[$ngaugeCode] = [
                    'magento_field' => $suggestion,
                    'confidence' => $confidence,
                    'ngauge_label' => $ngaugeField['label'],
                    'magento_label' => $magentoFields[$suggestion]['label'] ?? $suggestion,
                    'reason' => $this->getMatchReason($ngaugeCode, $suggestion, $confidence)
                ];
            }
        }
        
        // Sort by confidence
        uasort($suggestions, function($a, $b) {
            return $b['confidence'] <=> $a['confidence'];
        });
        
        return $suggestions;
    }

    /**
     * Validate field mapping configuration
     * 
     * @param array $mapping
     * @return array Validation results
     */
    public function validateMapping($mapping)
    {
        $ngaugeFields = $this->getNGaugeFields();
        $magentoFields = $this->getMagentoFields();
        $errors = [];
        $warnings = [];
        
        // Debug logging
        if (YII_ENV_DEV) {
            Yii::info("Validating mapping with " . count($mapping) . " entries", 'magento.field_mapping');
            Yii::info("Available Magento fields: " . count($magentoFields), 'magento.field_mapping');
        }
        
        foreach ($mapping as $ngaugeField => $magentoField) {
            // Check if NGauge field exists
            if (!isset($ngaugeFields[$ngaugeField])) {
                $errors[] = "NGauge field '$ngaugeField' does not exist";
                continue;
            }
            
            // Check if Magento field exists
            if (!isset($magentoFields[$magentoField])) {
                $errors[] = "Magento field '$magentoField' does not exist";
                continue;
            }
            
            // Check type compatibility
            $ngaugeType = $ngaugeFields[$ngaugeField]['type'];
            $magentoType = $magentoFields[$magentoField]['type'];
            
            if (!$this->areTypesCompatible($ngaugeType, $magentoType)) {
                $warnings[] = "Type mismatch: NGauge field '$ngaugeField' ($ngaugeType) may not be compatible with Magento field '$magentoField' ($magentoType)";
            }
        }
        
        // Check for required Magento fields
        $requiredFields = array_filter($magentoFields, function($field) {
            return $field['required'] ?? false;
        });
        
        // Debug logging
        if (YII_ENV_DEV) {
            $requiredFieldCodes = array_keys($requiredFields);
            Yii::info("Required Magento fields: " . implode(', ', $requiredFieldCodes), 'magento.field_mapping');
        }
        
        $mappedMagentoFields = array_values($mapping);
        
        // Debug logging
        if (YII_ENV_DEV) {
            Yii::info("Mapped Magento fields: " . implode(', ', $mappedMagentoFields), 'magento.field_mapping');
        }
        
        foreach ($requiredFields as $code => $field) {
            if (!in_array($code, $mappedMagentoFields)) {
                $warnings[] = "Required Magento field '$code' ({$field['label']}) is not mapped";
            }
        }
        
        return [
            'valid' => empty($errors),
            'errors' => $errors,
            'warnings' => $warnings
        ];
    }

    /**
     * Detect NGauge field type based on field name and characteristics
     * 
     * @param string $fieldName
     * @return string
     */
    protected function detectNGaugeFieldType($fieldName)
    {
        // Price fields
        if (preg_match('/^(price\d*|dmprice)$/', $fieldName)) {
            return 'price';
        }
        
        // Text/description fields
        if (preg_match('/(description|details|url)/', $fieldName)) {
            return 'textarea';
        }
        
        // ID fields
        if (preg_match('/(_id|^id)$/', $fieldName)) {
            return 'number';
        }
        
        // Status/boolean fields
        if (preg_match('/(status|deleted|active)/', $fieldName)) {
            return 'select';
        }
        
        // Weight/numeric fields
        if (preg_match('/(weight|qty|stock)/', $fieldName)) {
            return 'number';
        }
        
        // Date fields
        if (preg_match('/(created_at|updated_at|deleted_at)/', $fieldName)) {
            return 'datetime';
        }
        
        return 'text';
    }

    /**
     * Categorize NGauge field
     * 
     * @param string $fieldName
     * @return string
     */
    protected function categorizeNGaugeField($fieldName)
    {
        if (in_array($fieldName, ['id', 'product_id', 'stock_code', 'product_code', 'alt_stock_code'])) {
            return 'identification';
        }
        
        if (in_array($fieldName, ['product_name', 'displayname', 'brand', 'weight', 'status'])) {
            return 'basic';
        }
        
        if (preg_match('/^(price\d*|dmprice)$/', $fieldName) || in_array($fieldName, ['default_tax', 'price_group'])) {
            return 'pricing';
        }
        
        if (preg_match('/(description|details|url|model_name)/', $fieldName)) {
            return 'content';
        }
        
        if (preg_match('/(stock|qty|pack_qty|webstock)/', $fieldName)) {
            return 'stock';
        }
        
        if (preg_match('/(created|updated|deleted|sync)/', $fieldName)) {
            return 'system';
        }
        
        return 'other';
    }

    /**
     * Get category label
     * 
     * @param string $category
     * @return string
     */
    protected function getCategoryLabel($category)
    {
        $labels = [
            'identification' => 'Product Identification',
            'basic' => 'Basic Information',
            'pricing' => 'Pricing & Tax',
            'content' => 'Content & Descriptions',
            'stock' => 'Stock & Inventory',
            'system' => 'System Fields',
            'other' => 'Other Fields'
        ];
        
        return $labels[$category] ?? ucfirst($category);
    }

    /**
     * Calculate similarity between two fields
     * 
     * @param array $ngaugeField
     * @param array $magentoField
     * @return int Similarity score (0-100)
     */
    protected function calculateFieldSimilarity($ngaugeField, $magentoField)
    {
        $score = 0;
        
        // Compare field codes
        $codeScore = $this->stringSimilarity($ngaugeField['code'], $magentoField['code']);
        $score += $codeScore * 0.4;
        
        // Compare labels
        $labelScore = $this->stringSimilarity($ngaugeField['label'], $magentoField['label']);
        $score += $labelScore * 0.4;
        
        // Type compatibility bonus
        if ($this->areTypesCompatible($ngaugeField['type'], $magentoField['type'])) {
            $score += 20;
        }
        
        return min(100, (int)$score);
    }

    /**
     * Calculate string similarity percentage
     * 
     * @param string $str1
     * @param string $str2
     * @return float
     */
    protected function stringSimilarity($str1, $str2)
    {
        $str1 = strtolower($str1);
        $str2 = strtolower($str2);
        
        similar_text($str1, $str2, $percent);
        return $percent;
    }

    /**
     * Check if field types are compatible
     * 
     * @param string $ngaugeType
     * @param string $magentoType
     * @return bool
     */
    protected function areTypesCompatible($ngaugeType, $magentoType)
    {
        $compatibilityMap = [
            'text' => ['text', 'textarea', 'select'],
            'textarea' => ['text', 'textarea'],
            'number' => ['text', 'price', 'select'],
            'price' => ['price', 'text'],
            'select' => ['select', 'text'],
            'datetime' => ['text']
        ];
        
        return in_array($magentoType, $compatibilityMap[$ngaugeType] ?? []);
    }

    /**
     * Get match reason explanation
     * 
     * @param string $ngaugeField
     * @param string $magentoField
     * @param int $confidence
     * @return string
     */
    protected function getMatchReason($ngaugeField, $magentoField, $confidence)
    {
        if ($confidence === 100) {
            return 'Exact field name match';
        } elseif ($confidence >= 90) {
            return 'Very strong similarity match';
        } elseif ($confidence >= 70) {
            return 'Pattern-based match';
        } else {
            return 'Fuzzy similarity match';
        }
    }

    /**
     * Get default Magento fields (fallback)
     * 
     * @return array
     */
    protected function getDefaultMagentoFields()
    {
        return [
            'sku' => ['code' => 'sku', 'label' => 'SKU', 'type' => 'text', 'required' => true],
            'name' => ['code' => 'name', 'label' => 'Product Name', 'type' => 'text', 'required' => true],
            'price' => ['code' => 'price', 'label' => 'Price', 'type' => 'price', 'required' => false],
            'special_price' => ['code' => 'special_price', 'label' => 'Special Price', 'type' => 'price', 'required' => false],
            'description' => ['code' => 'description', 'label' => 'Description', 'type' => 'textarea', 'required' => false],
            'short_description' => ['code' => 'short_description', 'label' => 'Short Description', 'type' => 'textarea', 'required' => false],
            'weight' => ['code' => 'weight', 'label' => 'Weight', 'type' => 'text', 'required' => false],
            'status' => ['code' => 'status', 'label' => 'Status', 'type' => 'select', 'required' => true],
            'visibility' => ['code' => 'visibility', 'label' => 'Visibility', 'type' => 'select', 'required' => true],
        ];
    }

    /**
     * Get default categorized Magento fields (fallback)
     * 
     * @return array
     */
    protected function getDefaultCategorizedMagentoFields()
    {
        $fields = $this->getDefaultMagentoFields();
        
        return [
            'basic' => [
                'label' => 'Basic Information',
                'fields' => array_intersect_key($fields, array_flip(['sku', 'name', 'status', 'visibility', 'weight']))
            ],
            'pricing' => [
                'label' => 'Pricing',
                'fields' => array_intersect_key($fields, array_flip(['price', 'special_price']))
            ],
            'content' => [
                'label' => 'Content & SEO',
                'fields' => array_intersect_key($fields, array_flip(['description', 'short_description']))
            ]
        ];
    }
}