<?php
/**
 * @author 1902 Software
 * @copyright Copyright © 2023 1902 Software (https://1902software.com/magento/)
 * @package WriteTextAI_WriteTextAI
 */

declare(strict_types=1);

namespace WriteTextAI\WriteTextAI\Helper;

use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
use Magento\Catalog\Model\ResourceModel\Product\Collection;
use Magento\Eav\Api\AttributeRepositoryInterface;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Store\Model\StoreManagerInterface;
use Psr\Log\LoggerInterface;

class ProductDataHelper
{
    /**
     * Batch size for processing products
     */
    private const BATCH_SIZE = 100;

    /**
     * @var CollectionFactory
     */
    private $productCollectionFactory;

    /**
     * @var AttributeRepositoryInterface
     */
    private $attributeRepository;

    /**
     * @var SearchCriteriaBuilder
     */
    private $searchCriteriaBuilder;

    /**
     * @var StoreManagerInterface
     */
    private $storeManager;

    /**
     * @var LoggerInterface
     */
    private $logger;

    /**
     * Cache for product attributes to avoid repeated loading
     *
     * @var array
     */
    private $attributeCache = [];

    /**
     * Constructor
     *
     * @param CollectionFactory $productCollectionFactory
     * @param AttributeRepositoryInterface $attributeRepository
     * @param SearchCriteriaBuilder $searchCriteriaBuilder
     * @param StoreManagerInterface $storeManager
     * @param LoggerInterface $logger
     */
    public function __construct(
        CollectionFactory $productCollectionFactory,
        AttributeRepositoryInterface $attributeRepository,
        SearchCriteriaBuilder $searchCriteriaBuilder,
        StoreManagerInterface $storeManager,
        LoggerInterface $logger
    ) {
        $this->productCollectionFactory = $productCollectionFactory;
        $this->attributeRepository = $attributeRepository;
        $this->searchCriteriaBuilder = $searchCriteriaBuilder;
        $this->storeManager = $storeManager;
        $this->logger = $logger;
    }

    /**
     * Get all products data in batches for API submission
     *
     * @param int|null $storeId
     * @return \Generator
     */
    public function getProductsInBatches(?int $storeId = null): \Generator
    {
        try {
            if ($storeId === null) {
                $storeId = $this->storeManager->getStore()->getId();
            }

            $collection = $this->createOptimizedProductCollection($storeId);
            $totalProducts = $collection->getSize();
            
            if ($totalProducts === 0) {
                $this->logger->info('WriteTextAI ProductDataHelper: No products found for processing');
                return;
            }

            $this->logger->info(
                sprintf(
                    'WriteTextAI ProductDataHelper: Processing %d products in batches of %d',
                    $totalProducts,
                    self::BATCH_SIZE
                )
            );

            $pages = ceil($totalProducts / self::BATCH_SIZE);
            
            for ($page = 1; $page <= $pages; $page++) {
                $batchCollection = $this->createOptimizedProductCollection($storeId);
                $batchCollection->setPageSize(self::BATCH_SIZE);
                $batchCollection->setCurPage($page);

                $batchData = [];
                foreach ($batchCollection as $product) {
                    $productData = $this->extractProductData($product, $storeId);
                    if (!empty($productData)) {
                        $batchData[] = $productData;
                    }
                }

                if (!empty($batchData)) {
                    yield [
                        'products' => $batchData,
                        'batch_info' => [
                            'current_page' => $page,
                            'total_pages' => $pages,
                            'batch_size' => count($batchData),
                            'total_products' => $totalProducts
                        ]
                    ];
                }

                // Clear collection to free memory
                $batchCollection->clear();
                unset($batchCollection);
            }
        } catch (\Exception $e) {
            $this->logger->error(
                'WriteTextAI ProductDataHelper: Error processing products: ' . $e->getMessage(),
                ['exception' => $e]
            );
            throw $e;
        }
    }

    /**
     * Create optimized product collection
     *
     * @param int $storeId
     * @return Collection
     */
    private function createOptimizedProductCollection(int $storeId): Collection
    {
        $collection = $this->productCollectionFactory->create();
        
        // Set store context
        $collection->setStoreId($storeId);
        
        // Only load enabled products
        $collection->addAttributeToFilter(
            'status',
            \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED
        );
        
        // Only load visible products
        $collection->addAttributeToFilter(
            'visibility',
            ['in' => [
                \Magento\Catalog\Model\Product\Visibility::VISIBILITY_IN_CATALOG,
                \Magento\Catalog\Model\Product\Visibility::VISIBILITY_IN_SEARCH,
                \Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH
            ]]
        );

        // Load essential attributes
        $collection->addAttributeToSelect([
            'entity_id',
            'sku',
            'name',
            'type_id',
            'attribute_set_id'
        ]);

        // Load all custom attributes
        $collection->addAttributeToSelect('*');

        return $collection;
    }

    /**
     * Extract product data for API submission
     *
     * @param \Magento\Catalog\Model\Product $product
     * @param int $storeId
     * @return array
     */
    private function extractProductData(\Magento\Catalog\Model\Product $product, int $storeId): array
    {
        try {
            $productData = [
                'entity_id' => $product->getId(),
                'sku' => $product->getSku(),
                'name' => $product->getName(),
                'type_id' => $product->getTypeId(),
                'attribute_set_id' => $product->getAttributeSetId(),
                'store_id' => $storeId,
                'attributes' => []
            ];

            // Get all product attributes and their values
            $attributes = $product->getAttributes();
            
            foreach ($attributes as $attribute) {
                $attributeCode = $attribute->getAttributeCode();
                
                // Skip system attributes that are not relevant for AI processing
                if ($this->shouldSkipAttribute($attributeCode)) {
                    continue;
                }

                $value = $product->getData($attributeCode);
                
                // Skip empty values
                if ($value === null || $value === '' || $value === false) {
                    continue;
                }

                // Handle different attribute types
                $formattedValue = $this->formatAttributeValue($attribute, $value, $product);
                
                if ($formattedValue !== null) {
                    $productData['attributes'][$attributeCode] = [
                        'label' => $attribute->getStoreLabel($storeId) ?: $attribute->getFrontendLabel(),
                        'value' => $formattedValue,
                        'type' => $attribute->getFrontendInput()
                    ];
                }
            }

            return $productData;
        } catch (\Exception $e) {
            $this->logger->error(
                sprintf(
                    'WriteTextAI ProductDataHelper: Error extracting data for product ID %d: %s',
                    $product->getId(),
                    $e->getMessage()
                )
            );
            return [];
        }
    }

    /**
     * Check if attribute should be skipped
     *
     * @param string $attributeCode
     * @return bool
     */
    private function shouldSkipAttribute(string $attributeCode): bool
    {
        $skipAttributes = [
            'entity_id',
            'created_at',
            'updated_at',
            'has_options',
            'required_options',
            'entity_type_id',
            'attribute_set_id',
            'type_id',
            'sku',
            'links_purchased_separately',
            'links_exist',
            'tier_price',
            'media_gallery',
            'gallery'
        ];

        return in_array($attributeCode, $skipAttributes);
    }

    /**
     * Format attribute value based on attribute type
     *
     * @param \Magento\Eav\Model\Entity\Attribute $attribute
     * @param mixed $value
     * @param \Magento\Catalog\Model\Product $product
     * @return mixed
     */
    private function formatAttributeValue($attribute, $value, $product)
    {
        $frontendInput = $attribute->getFrontendInput();
        
        try {
            switch ($frontendInput) {
                case 'select':
                case 'multiselect':
                    return $product->getAttributeText($attribute->getAttributeCode()) ?: $value;
                    
                case 'boolean':
                    return $value ? 'Yes' : 'No';
                    
                case 'price':
                    return is_numeric($value) ? (float)$value : $value;
                    
                case 'weight':
                    return is_numeric($value) ? (float)$value : $value;
                    
                case 'date':
                case 'datetime':
                    if ($value) {
                        return date('Y-m-d H:i:s', strtotime($value));
                    }
                    return $value;
                    
                case 'textarea':
                case 'text':
                default:
                    // Clean HTML for text fields if needed
                    if (is_string($value) && strlen($value) > 1000) {
                        // Truncate very long text to avoid API payload issues
                        return substr(strip_tags($value), 0, 1000) . '...';
                    }
                    return is_string($value) ? strip_tags($value) : $value;
            }
        } catch (\Exception $e) {
            $this->logger->warning(
                sprintf(
                    'WriteTextAI ProductDataHelper: Error formatting attribute %s: %s',
                    $attribute->getAttributeCode(),
                    $e->getMessage()
                )
            );
            return $value;
        }
    }

    /**
     * Get batch size
     *
     * @return int
     */
    public function getBatchSize(): int
    {
        return self::BATCH_SIZE;
    }

    /**
     * Get total products count
     *
     * @param int|null $storeId
     * @return int
     */
    public function getTotalProductsCount(?int $storeId = null): int
    {
        try {
            if ($storeId === null) {
                $storeId = $this->storeManager->getStore()->getId();
            }

            $collection = $this->createOptimizedProductCollection($storeId);
            return $collection->getSize();
        } catch (\Exception $e) {
            $this->logger->error(
                'WriteTextAI ProductDataHelper: Error getting total products count: ' . $e->getMessage()
            );
            return 0;
        }
    }
}
