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

declare(strict_types=1);

namespace WriteTextAI\WriteTextAI\Cron;

use WriteTextAI\WriteTextAI\Helper\ProductDataHelper;
use WriteTextAI\WriteTextAI\Model\Api\AIModels;
use Magento\Store\Model\StoreManagerInterface;
use Psr\Log\LoggerInterface;
use WriteTextAI\WriteTextAI\Helper\Store as StoreHelper;
use WriteTextAI\WriteTextAI\Helper\Fields as FieldHelper;
use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory as CategoryCollectionFactory;
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory as ProductCollectionFactory;
use Magento\Catalog\Helper\Output as OutputHelper;
use WriteTextAI\WriteTextAI\Helper\Data as DataHelper;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Store\Model\ScopeInterface;
use Magento\Catalog\Model\ProductFactory;
use Magento\UrlRewrite\Service\V1\Data\UrlRewrite as UrlRewriteData;
use Magento\UrlRewrite\Model\UrlFinderInterface;
use Magento\Framework\App\State;

class AiModelCron extends BaseCron
{
    /**
     * @var ProductDataHelper
     */
    private $productDataHelper;

    /**
     * @var AIModels
     */
    private $aiModels;

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

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

    /**
     * @var StoreHelper
     */
    private $storeHelper;

    /**
     * @var FieldHelper
     */
    private $fieldHelper;

    /**
     * @var CategoryCollectionFactory
     */
    private $categoryCollectionFactory;

    /**
     * @var OutputHelper
     */
    private $outputHelper;

    /**
     * @var DataHelper
     */
    private $dataHelper;

    /**
     * @var ScopeConfigInterface
     */
    protected $scopeConfig;

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

    /**
     * @var UrlFinderInterface
     */
    private $urlFinder;

    /**
     * @var State
     */
    private $state;

    /**
     * Constructor
     *
     * @param \Magento\User\Model\UserFactory $userFactory
     * @param \WriteTextAI\WriteTextAI\Model\Api\Session $apiSession
     * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
     * @param ProductDataHelper $productDataHelper
     * @param AIModels $aiModels
     * @param StoreManagerInterface $storeManager
     * @param LoggerInterface $logger
     * @param StoreHelper $storeHelper
     * @param FieldHelper $fieldHelper
     * @param CategoryCollectionFactory $categoryCollectionFactory
     * @param OutputHelper $outputHelper
     * @param DataHelper $dataHelper
     * @param ProductCollectionFactory $productCollectionFactory
     * @param UrlFinderInterface $urlFinder
     * @param State $state
     */
    public function __construct(
        \Magento\User\Model\UserFactory $userFactory,
        \WriteTextAI\WriteTextAI\Model\Api\Session $apiSession,
        \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
        ProductDataHelper $productDataHelper,
        AIModels $aiModels,
        StoreManagerInterface $storeManager,
        LoggerInterface $logger,
        StoreHelper $storeHelper,
        FieldHelper $fieldHelper,
        CategoryCollectionFactory $categoryCollectionFactory,
        OutputHelper $outputHelper,
        DataHelper $dataHelper,
        ProductCollectionFactory $productCollectionFactory,
        UrlFinderInterface $urlFinder,
        State $state
    ) {
        parent::__construct($userFactory, $apiSession, $scopeConfig);
        $this->scopeConfig = $scopeConfig;
        $this->productDataHelper = $productDataHelper;
        $this->aiModels = $aiModels;
        $this->storeManager = $storeManager;
        $this->logger = $logger;
        $this->storeHelper = $storeHelper;
        $this->fieldHelper = $fieldHelper;
        $this->categoryCollectionFactory = $categoryCollectionFactory;
        $this->outputHelper = $outputHelper;
        $this->dataHelper = $dataHelper;
        $this->productCollectionFactory = $productCollectionFactory;
        $this->urlFinder = $urlFinder;
        $this->state = $state;
    }

    /**
     * Execute AI model cron job to send all products to API
     *
     * @return void
     */
    public function execute(): void
    {
        try {
            $this->state->setAreaCode(\Magento\Framework\App\Area::AREA_ADMINHTML);
            
            $this->logger->info('WriteTextAI AiModelCron: Starting AI model cron execution');

            // Get all stores to process products for each store
            $stores = $this->storeManager->getStores();
            
            foreach ($stores as $store) {
                $storeId = (int)$store->getId();
                
                if (!$this->isAiModelSyncEnabled($storeId)) {
                    $this->logger->info(
                        sprintf(
                            'WriteTextAI AiModelCron: AI Model Sync is disabled for store %d',
                            $storeId
                        )
                    );
                    continue;
                }
                
                $this->processStoreProducts($storeId);
                $this->processStoreCategories($storeId);
            }

            $this->logger->info('WriteTextAI AiModelCron: AI model cron execution completed successfully');
        } catch (\Exception $e) {
            $this->logger->error(
                'WriteTextAI AiModelCron: Error during execution: ' . $e->getMessage(),
                ['exception' => $e]
            );
            return;
        }
    }

    /**
     * Process products for a specific store
     *
     * @param int $storeId
     * @return void
     */
    private function processStoreProducts(int $storeId): void
    {
        try {
            $this->logger->info(
                sprintf('WriteTextAI AiModelCron: Processing products for store ID: %d', $storeId)
            );

            $totalProducts = $this->productDataHelper->getTotalProductsCount($storeId);
            
            if ($totalProducts === 0) {
                $this->logger->info(
                    sprintf('WriteTextAI AiModelCron: No products found for store ID: %d', $storeId)
                );
                return;
            }

            $batchNumber = 0;
            $successfulBatches = 0;
            $failedBatches = 0;

            // Process products in batches
            foreach ($this->productDataHelper->getProductsInBatches($storeId) as $batch) {
                $batchNumber++;
                
                try {
                    $this->logger->info(
                        sprintf(
                            'WriteTextAI AiModelCron: Processing batch %d/%d for store %d (%d products)',
                            $batch['batch_info']['current_page'],
                            $batch['batch_info']['total_pages'],
                            $storeId,
                            $batch['batch_info']['batch_size']
                        )
                    );

                    // Transform product data into API payload format
                    $transformedProducts = $this->transformProductsData($batch['products'], $storeId);
                    
                    // Prepare data for API with correct structure
                    $apiData = [
                        'products' => $transformedProducts,
                        'categories' => []
                    ];

                    // Send data to API using existing sendProductsData method
                    $response = $this->aiModels->sendProductsData($apiData);

                    if ($this->isApiResponseSuccessful($response)) {
                        $successfulBatches++;
                        $this->logger->info(
                            sprintf(
                                'WriteTextAI AiModelCron: Successfully sent batch %d for store %d',
                                $batchNumber,
                                $storeId
                            )
                        );
                    } else {
                        $failedBatches++;
                        $this->logger->error(
                            sprintf(
                                'WriteTextAI AiModelCron: Failed to send batch %d for store %d. Response: %s',
                                $batchNumber,
                                $storeId,
                                json_encode($response)
                            )
                        );
                    }
                } catch (\Exception $e) {
                    $failedBatches++;
                    $this->logger->error(
                        sprintf(
                            'WriteTextAI AiModelCron: Error processing batch %d for store %d: %s',
                            $batchNumber,
                            $storeId,
                            $e->getMessage()
                        ),
                        ['exception' => $e]
                    );
                }

                // Add small delay between batches to avoid overwhelming the API
                usleep(100000); // 100ms delay
            }

            $this->logger->info(
                sprintf(
                    'WriteTextAI AiModelCron: Completed processing store %d.'
                        . ' Successful batches: %d, Failed batches: %d',
                    $storeId,
                    $successfulBatches,
                    $failedBatches
                )
            );
        } catch (\Exception $e) {
            $this->logger->error(
                sprintf(
                    'WriteTextAI AiModelCron: Error processing store %d: %s',
                    $storeId,
                    $e->getMessage()
                ),
                ['exception' => $e]
            );
        }
    }

    /**
     * Transform product data into API payload format
     *
     * @param array $products
     * @param int $storeId
     * @return array
     */
    public function transformProductsData(array $products, int $storeId): array
    {
        $transformedProducts = [];
        
        foreach ($products as $product) {
            $productId = $product['entity_id'] ?? null;
            
            if (!$productId) {
                continue;
            }
            
            $productObject = $this->productCollectionFactory->create()
                ->setStoreId($storeId)
                ->addAttributeToSelect('*')
                ->addAttributeToFilter('entity_id', $productId)
                ->setPageSize(1)
                ->getFirstItem();
            
            if (!$productObject || !$productObject->getId()) {
                continue;
            }

            $productName = (string)$this->outputHelper->productAttribute(
                $productObject,
                $productObject->getName(),
                'name'
            );

            $customOpenGraph = $this->dataHelper->getCustomOpenGraph();
            $openGraphText = '';
            if ($customOpenGraph) {
                $openGraphText = $this->fieldHelper->getAttributesValues($productObject, 'open_graph') ?? '';
            } else {
                $openGraphText = $this->fieldHelper->getAttributesValues(
                    $productObject,
                    'short_product_description'
                ) ?? '';
            }

            $transformedProduct = [
                'recordId' => (string)$productObject->getId(),
                'language' => $this->getLanguageCode($storeId),
                'name' => $productName,
                'pageTitle' => $this->fieldHelper->getAttributesValues($productObject, 'page_title')
                    ?? '',
                'pageDescription' => $this->fieldHelper->getAttributesValues(
                    $productObject,
                    'page_description'
                ) ?? '',
                'excerpt' => $this->fieldHelper->getAttributesValues(
                    $productObject,
                    'short_product_description'
                ) ?? '',
                'openGraphText' => $openGraphText,
                'productDescription' => $this->fieldHelper->getAttributesValues(
                    $productObject,
                    'product_description'
                ) ?? '',
                'sku' => $productObject->getSku() ?? '',
                'url' => $this->getProductUrl($product, $storeId),
                'categoryRecordIds' => $this->getCategoryRecordIds($productObject)
            ];
            
            $transformedProducts[] = $transformedProduct;
        }
        
        return $transformedProducts;
    }

    /**
     * Get attribute value from product data
     *
     * @param array $product
     * @param string $attributeCode
     * @return string|null
     */
    private function getAttributeValue(array $product, string $attributeCode): ?string
    {
        if (isset($product['attributes'][$attributeCode]['value'])) {
            $value = $product['attributes'][$attributeCode]['value'];
            return is_string($value) ? $value : (string)$value;
        }
        return null;
    }

    /**
     * Get product URL
     *
     * @param array $product
     * @param int $storeId
     * @return string
     */
    private function getProductUrl(array $product, int $storeId): string
    {
        try {
            $frontendStoreId = $this->storeHelper->getFrontendStoreId($storeId);
            $productId = $product['entity_id'] ?? null;
            
            if (!$productId) {
                return '';
            }
            
            $productObject = $this->productCollectionFactory->create()
                ->setStoreId($frontendStoreId)
                ->addAttributeToSelect('*')
                ->addAttributeToFilter('entity_id', $productId)
                ->setPageSize(1)
                ->getFirstItem();
            
            if (!$productObject || !$productObject->getId()) {
                return '';
            }
            
            return $productObject->setStoreId($frontendStoreId)->getUrlInStore();
        } catch (\Exception $e) {
            $this->logger->warning(
                'WriteTextAI AiModelCron: Error getting product URL: ' . $e->getMessage()
            );
            return '';
        }
    }

    /**
     * Get category record IDs for product
     *
     * @param \Magento\Catalog\Model\Product $product
     * @return array
     */
    private function getCategoryRecordIds($product): array
    {
        $categoryIds = $product->getCategoryIds();
        if (!$categoryIds) {
            return [];
        }
        
        return array_map('strval', $categoryIds);
    }

    /**
     * Get and transform categories for API payload
     *
     * @param int $storeId
     * @return array
     */
    public function getTransformedCategories(int $storeId): array
    {
        try {
            $mappingSettings = $this->dataHelper->getMappingSettings();
            $attributesToSelect = [
                'entity_id',
                'name',
                'meta_title',
                'meta_description',
                $mappingSettings['category_description'] ?? 'description'
            ];
            $collection = $this->categoryCollectionFactory->create();
            $collection->setStoreId($storeId);
            $collection->addAttributeToSelect($attributesToSelect);
            $collection->addAttributeToFilter('is_active', 1);
            
            $transformedCategories = [];
            foreach ($collection as $category) {
                $transformedCategory = [
                    'recordId' => (string)$category->getId(),
                    'language' => $this->getLanguageCode($storeId),
                    'name' => $category->getName() ?? '',
                    'pageTitle' => (string)$category->getMetaTitle(),
                    'pageDescription' => (string)$category->getMetaDescription(),
                    'categoryDescription' => (string)$this->outputHelper->categoryAttribute(
                        $category,
                        $category->getData(
                            $mappingSettings['category_description'] ?? 'description'
                        ),
                        $mappingSettings['category_description'] ?? 'description'
                    ),
                    'url' => $this->getCategoryUrl($category, $storeId)
                ];
                
                $transformedCategories[] = $transformedCategory;
            }
            
            return $transformedCategories;
        } catch (\Exception $e) {
            $this->logger->error(
                'WriteTextAI AiModelCron: Error getting categories: ' . $e->getMessage(),
                ['exception' => $e]
            );
            return [];
        }
    }

    /**
     * Get language code for current store
     *
     * @param int $storeId
     * @return string
     */
    private function getLanguageCode(int $storeId): string
    {
        try {
            return $this->storeHelper->getFormattedLanguage($storeId);
        } catch (\Exception $e) {
            $this->logger->warning(
                'WriteTextAI AiModelCron: Error getting language code: ' . $e->getMessage()
            );
            return 'en';
        }
    }

    /**
     * Get category URL
     *
     * @param \Magento\Catalog\Model\Category $category
     * @param int $storeId
     * @return string
     */
    private function getCategoryUrl($category, int $storeId): string
    {
        try {
            $categoryId = $category->getId();
            $rewrite = $this->urlFinder->findOneByData([
                UrlRewriteData::ENTITY_ID => $categoryId,
                UrlRewriteData::ENTITY_TYPE => 'category',
                UrlRewriteData::STORE_ID => $storeId
            ]);
            
            $category->getUrlInstance()->setScope($storeId);
            
            $targetPath = (!$rewrite) ? $category->getUrl() :
                $this->storeManager->getStore($storeId)->getBaseUrl() . $rewrite->getRequestPath();

            return $targetPath;
        } catch (\Exception $e) {
            $this->logger->warning(
                'WriteTextAI AiModelCron: Error getting category URL: ' . $e->getMessage()
            );
            return '';
        }
    }

    /**
     * Process categories for a specific store
     *
     * @param int $storeId
     * @return void
     */
    private function processStoreCategories(int $storeId): void
    {
        try {
            $this->logger->info(
                sprintf('WriteTextAI AiModelCron: Processing categories for store ID: %d', $storeId)
            );

            $transformedCategories = $this->getTransformedCategories($storeId);
            
            if (empty($transformedCategories)) {
                $this->logger->info(
                    sprintf('WriteTextAI AiModelCron: No categories found for store ID: %d', $storeId)
                );
                return;
            }

            $apiData = [
                'products' => [],
                'categories' => $transformedCategories
            ];

            $response = $this->aiModels->sendProductsData($apiData);

            if ($this->isApiResponseSuccessful($response)) {
                $this->logger->info(
                    sprintf(
                        'WriteTextAI AiModelCron: Successfully sent %d categories for store %d',
                        count($transformedCategories),
                        $storeId
                    )
                );
            } else {
                $this->logger->error(
                    sprintf(
                        'WriteTextAI AiModelCron: Failed to send categories for store %d. Response: %s',
                        $storeId,
                        json_encode($response)
                    )
                );
            }
        } catch (\Exception $e) {
            $this->logger->error(
                sprintf(
                    'WriteTextAI AiModelCron: Error processing categories for store %d: %s',
                    $storeId,
                    $e->getMessage()
                ),
                ['exception' => $e]
            );
        }
    }

    /**
     * Check if AI Model Sync is enabled for a store
     *
     * @param int $storeId
     * @return bool
     */
    private function isAiModelSyncEnabled(int $storeId): bool
    {
        return (bool)$this->scopeConfig->getValue(
            'writetextai_settings/cron/ai_model_enabled',
            ScopeInterface::SCOPE_STORE,
            $storeId
        );
    }

    /**
     * Check if API response is successful
     *
     * @param array|null $response
     * @return bool
     */
    private function isApiResponseSuccessful($response): bool
    {
        if (!is_array($response)) {
            return false;
        }

        // Check for common success indicators
        if (isset($response['success']) && $response['success'] === true) {
            return true;
        }

        if (isset($response['status']) && in_array($response['status'], ['success', 'ok', '200'])) {
            return true;
        }

        // If no error indicators are present, consider it successful
        if (!isset($response['error']) && !isset($response['errors'])) {
            return true;
        }

        return false;
    }
}
