<?php
namespace EasyChat\Library\Ai;

use EasyChat\Library\Logger;
use EasyChat\Library\Queue\QueueManager;
use D1medrol\MysqlVector\VectorTable;










class VectorStorageGuard {

    public static function ensureCompatible($registry, string $storage_name, int $dimension, int $current_knowledge_id = 0): array {
        $db = $registry->get('db');
        $mysqli = $db->getRawConnection();

        $vector_table = new VectorTable($mysqli, $storage_name, $dimension);
        $vector_table->initialize(true, true);

        $status = self::status($registry, $storage_name, $dimension);
        if (!empty($status['compatible'])) {
            return $status + ['rebuilt' => false, 'requeued' => 0];
        }

        $vector_count = self::countRows($db, $status['vector_table']);

        self::dropStorage($db, $status['vector_table'], $status['meta_table']);
        $vector_table = new VectorTable($mysqli, $storage_name, $dimension);
        $vector_table->initialize(true, true);

        $requeued = 0;
        if ($vector_count > 0) {
            $requeued = self::requeueActiveKnowledge($registry, $current_knowledge_id);
        }

        if (class_exists('Logger')) {
            Logger::warning(
                'Vector storage rebuilt for dimension ' . $dimension . '; requeued=' . $requeued,
                'queue.log'
            );
        }

        $status = self::status($registry, $storage_name, $dimension);
        return $status + ['rebuilt' => true, 'requeued' => $requeued];
    }

    public static function status($registry, string $storage_name, int $dimension): array {
        $db = $registry->get('db');
        $vector_table = $storage_name . '_vectors';
        $meta_table = $vector_table . '_meta';
        $expected_bytes = (int)ceil($dimension / 8);
        $actual_bytes = self::binaryCodeBytes($db, $vector_table);
        $vector_exists = self::tableExists($db, $vector_table);
        $meta_exists = self::tableExists($db, $meta_table);
        $compatible = $vector_exists && $meta_exists && $actual_bytes === $expected_bytes;

        $reason = '';
        if (!$vector_exists) {
            $reason = 'vector_table_missing';
        } elseif (!$meta_exists) {
            $reason = 'meta_table_missing';
        } elseif ($actual_bytes !== $expected_bytes) {
            $reason = 'dimension_mismatch';
        }

        return [
            'compatible' => $compatible,
            'reason' => $reason,
            'dimension' => $dimension,
            'expected_binary_code_bytes' => $expected_bytes,
            'actual_binary_code_bytes' => $actual_bytes,
            'vector_table' => $vector_table,
            'meta_table' => $meta_table,
        ];
    }

    private static function requeueActiveKnowledge($registry, int $current_knowledge_id): int {

        $db = $registry->get('db');
        $p = easychat_db_prefix();
        $current_knowledge_id = max(0, $current_knowledge_id);

        $result = $db->query(
            "SELECT id, title, content, section_id, status
             FROM `{$p}knowledge`
             WHERE vector_id IS NOT NULL
               AND status IN ('active', 'indexing', 'disabled')"
        );
        $rows = $result->rows ?? [];

        if (empty($rows)) {
            return 0;
        }

        $ids = array_map('intval', array_column($rows, 'id'));
        $db->query(
            "UPDATE `{$p}knowledge`
             SET vector_id = NULL,
                 status = CASE WHEN status = 'disabled' THEN 'disabled' ELSE 'pending' END,
                 error = NULL,
                 date_modified = NOW()
             WHERE id IN (" . implode(',', $ids) . ")"
        );

        $queue = new QueueManager($registry);
        $requeued = 0;
        foreach ($rows as $row) {
            $knowledge_id = (int)$row['id'];
            if ($knowledge_id === $current_knowledge_id) {
                continue;
            }

            $was_disabled = ((string)($row['status'] ?? '') === 'disabled');
            $queue->push('embedding', [
                'knowledge_id' => $knowledge_id,
                'text' => (string)$row['title'] . "\n\n" . (string)$row['content'],
                'item_id' => $knowledge_id,
                'section_id' => (int)$row['section_id'],
                'final_status' => $was_disabled ? 'disabled' : 'active',
                'meta' => [
                    'title' => (string)$row['title'],
                    'source' => 'dimension_rebuild',
                ],
            ], 0, 20);
            $requeued++;
        }

        return $requeued;
    }

    private static function binaryCodeBytes($db, string $table): ?int {
        $table_e = $db->escape($table);
        $result = $db->query(
            "SELECT CHARACTER_OCTET_LENGTH AS bytes
             FROM information_schema.columns
             WHERE table_schema = DATABASE()
               AND table_name = '{$table_e}'
               AND column_name = 'binary_code'
             LIMIT 1"
        );

        if (!$result || empty($result->row)) {
            return null;
        }

        return (int)$result->row['bytes'];
    }

    private static function tableExists($db, string $table): bool {
        $table_e = $db->escape($table);
        $result = $db->query(
            "SELECT COUNT(*) AS cnt
             FROM information_schema.tables
             WHERE table_schema = DATABASE()
               AND table_name = '{$table_e}'"
        );

        return (int)($result->row['cnt'] ?? 0) > 0;
    }

    private static function countRows($db, string $table): int {
        if (!self::tableExists($db, $table)) {
            return 0;
        }

        $table_sql = self::quoteIdentifier($table);
        $result = $db->query("SELECT COUNT(*) AS cnt FROM {$table_sql}");
        return (int)($result->row['cnt'] ?? 0);
    }

    private static function dropStorage($db, string $vector_table, string $meta_table): void {
        $db->query('DROP TABLE IF EXISTS ' . self::quoteIdentifier($meta_table));
        $db->query('DROP TABLE IF EXISTS ' . self::quoteIdentifier($vector_table));
    }

    private static function quoteIdentifier(string $name): string {
        return '`' . str_replace('`', '``', $name) . '`';
    }
}
