<?php
namespace EasyChat\Library\Queue\Jobs;

use EasyChat\KnowledgeSection;
use EasyChat\Library\Catalog\CatalogIndexScheduler;
use EasyChat\Library\Logger;
use EasyChat\Library\Queue\JobInterface;
use EasyChat\Library\Queue\QueueManager;
use EasyChat\Library\Queue\RequeueWithoutAttemptException;
use EasyChat\Model\Cms\CmsFactory;
use EasyChat\Model\Knowledge;
use EasyChat\Model\Setting;








class CmsIndexJob implements JobInterface {

    const BATCH_SIZE = 50;

    private $registry;

    public function __construct($registry) {
        $this->registry = $registry;
    }

    public function handle(array $payload): void {
        $model_setting = new Setting($this->registry);
        $settings = $model_setting->getAll();
        if ((string)($settings['chat_cms_semantic_enabled'] ?? '0') !== '1') {
            Logger::info('CmsIndexJob: semantic search disabled before batch start', 'queue.log');
            return;
        }
        $cms_type = (string)($settings['chat_cms_type'] ?? 'none');
        $cms_prefix = (string)($settings['chat_cms_prefix'] ?? '');
        if ($cms_type === 'none') {
            throw new \RuntimeException('CmsIndexJob: CMS не настроена');
        }

        $do_products = (string)($settings['chat_cms_index_products'] ?? '0') === '1';
        $do_pages = (string)($settings['chat_cms_index_pages'] ?? '0') === '1';
        if (!$do_products && !$do_pages) {
            Logger::info('CmsIndexJob: индексирование отключено', 'queue.log');
            return;
        }

        $current_signature = CatalogIndexScheduler::sourceSignature($settings);
        $payload_signature = strtolower(trim((string)($payload['source_signature'] ?? '')));
        $legacy_cursor_without_signature = $payload_signature === ''
            && (trim((string)($payload['generation'] ?? '')) !== ''
                || (int)($payload['after_id'] ?? 0) > 0);
        if ($legacy_cursor_without_signature
            || ($payload_signature !== ''
                && (!preg_match('/^[a-f0-9]{16}$/', $payload_signature)
                    || !hash_equals($current_signature, $payload_signature)))) {
            throw new RequeueWithoutAttemptException(
                'CMS index source changed; restart with a new generation',
                1,
                array(
                    'source' => CatalogIndexScheduler::firstEnabledSource($settings),
                    'source_signature' => $current_signature,
                    'generation' => bin2hex(random_bytes(8)),
                    'after_id' => 0,
                ),
                true
            );
        }
        $payload_signature = $current_signature;

        $source = (string)($payload['source'] ?? '');
        if (!in_array($source, array('products', 'pages'), true)) {
            $source = CatalogIndexScheduler::firstEnabledSource($settings);
        }
        if (($source === 'products' && !$do_products) || ($source === 'pages' && !$do_pages)) {
            return;
        }

        $generation = strtolower(trim((string)($payload['generation'] ?? '')));
        if (!preg_match('/^[a-f0-9]{16}$/', $generation)) {
            $generation = bin2hex(random_bytes(8));
        }
        $after_id = max(0, (int)($payload['after_id'] ?? 0));

        $db = $this->registry->get('db');
        $cms = CmsFactory::create($db, $cms_type, $cms_prefix, $settings);
        if (!$cms) {
            throw new \RuntimeException('CmsIndexJob: CMS adapter недоступен');
        }

        $rows = $source === 'products'
            ? $cms->getProductsBatch($after_id, self::BATCH_SIZE)
            : $cms->getPagesBatch($after_id, self::BATCH_SIZE);
        $section_id = $source === 'products' ? KnowledgeSection::PRODUCT : KnowledgeSection::PAGE;
        $knowledge = new Knowledge($this->registry);
        $queue = new QueueManager($this->registry);
        $queued = 0;
        $skipped = 0;
        $last_id = $after_id;

        foreach ($rows as $row) {
            $source_id = (int)($row['id'] ?? 0);
            if ($source_id <= 0) {
                continue;
            }
            $last_id = max($last_id, $source_id);
            $text = $source === 'products'
                ? $cms->getProductText($source_id)
                : $cms->getPageText($source_id);
            if (trim($text) === '') {
                continue;
            }

            $name = trim((string)($row['name'] ?? ''));
            if ($name === '') {
                $name = ($source === 'products' ? 'Товар #' : 'Страница #') . $source_id;
            }
            $entry = $knowledge->upsertCmsItem($name, $text, $section_id, $source_id, $generation);
            if (!empty($entry['skip'])) {
                $skipped++;
                continue;
            }

            $queue->push('embedding', array(
                'knowledge_id' => (int)$entry['id'],
                'text' => $text,
                'item_id' => $source_id,
                'section_id' => $section_id,
                'meta' => array(
                    'title' => $name,
                    'source' => $source === 'products' ? 'product' : 'page',
                    'source_id' => $source_id,
                ),
                'final_status' => (string)($entry['final_status'] ?? 'active'),
                'origin' => 'cms_index',
            ));
            $queued++;
        }

        if (count($rows) >= self::BATCH_SIZE && $last_id > $after_id) {
            Logger::info(
                'CmsIndexJob: source=' . $source . ' after_id=' . $after_id
                . ' rows=' . count($rows) . ' queued=' . $queued . ' unchanged=' . $skipped,
                'queue.log'
            );
            throw new RequeueWithoutAttemptException(
                'CMS index batch completed; continue from cursor ' . $last_id,
                1,
                array(
                    'source' => $source,
                    'source_signature' => $payload_signature,
                    'generation' => $generation,
                    'after_id' => $last_id,
                ),
                true
            );
        } else {
            $disabled = $knowledge->disableCmsItemsNotSeen($section_id, $generation);
            if ($source === 'products' && $do_pages) {
                throw new RequeueWithoutAttemptException(
                    'CMS product index completed; continue with public pages',
                    1,
                    array(
                        'source' => 'pages',
                        'source_signature' => $payload_signature,
                        'generation' => $generation,
                        'after_id' => 0,
                    ),
                    true
                );
            } else {
                $model_setting->set('chat_cms_last_indexed_at', date('c'));
            }
            Logger::info('CmsIndexJob: source=' . $source . ' generation=' . $generation . ' disabled=' . $disabled, 'queue.log');
        }

        Logger::info(
            'CmsIndexJob: source=' . $source . ' after_id=' . $after_id
            . ' rows=' . count($rows) . ' queued=' . $queued . ' unchanged=' . $skipped,
            'queue.log'
        );
    }
}
