/**
 * Inqyra Embeddings Module
 *
 * Browser-based embeddings using Transformers.js
 * This file must be loaded as a module (type="module")
 *
 * @package Inqyra
 */

let pipelineFactory = null;
let embeddingPipeline = null;
let isProcessing = false;

/**
 * Lazy-load Transformers.js on first use.
 */
async function loadTransformers() {
    if (pipelineFactory) return pipelineFactory;
    // Use the locally bundled Transformers.js library (URL provided by PHP via inqyraEmbeddingsConfig).
    const url = (window.inqyraEmbeddingsConfig && window.inqyraEmbeddingsConfig.transformersUrl)
        ? window.inqyraEmbeddingsConfig.transformersUrl
        : (window.inqyraAdmin && window.inqyraAdmin.transformersUrl);
    const module = await import(url);
    pipelineFactory = module.pipeline;
    return pipelineFactory;
}

/**
 * Initialize the embedding pipeline
 */
async function initPipeline(onProgress) {
    if (embeddingPipeline) {
        return embeddingPipeline;
    }

    const pipeline = await loadTransformers();

    embeddingPipeline = await pipeline('feature-extraction', 'Xenova/paraphrase-multilingual-MiniLM-L12-v2', {
        progress_callback: onProgress
    });

    return embeddingPipeline;
}

/**
 * Generate embedding for a text
 */
async function generateEmbedding(text) {
    const pipe = await initPipeline();
    const result = await pipe(text, {
        pooling: 'mean',
        normalize: true
    });
    return Array.from(result.data);
}

/**
 * Process embeddings for chunks
 * @param {string} ajaxUrl - WordPress AJAX URL
 * @param {string} nonce - Security nonce
 * @param {string} agentId - Agent ID
 * @param {function} onStatus - Callback: (status, message, data) where data contains extra info like chunkId
 */
async function processEmbeddings(ajaxUrl, nonce, agentId, onStatus) {
    if (isProcessing) {
        return { error: 'Already processing' };
    }

    isProcessing = true;
    const stats = { processed: 0, failed: 0, total: 0 };

    try {
        // Initialize pipeline
        onStatus('loading', 'Loading embedding model...', {});

        await initPipeline((progress) => {
            if (progress.status === 'downloading') {
                onStatus('downloading', `Downloading model: ${Math.round(progress.progress || 0)}%`, {});
            } else if (progress.status === 'loading') {
                onStatus('loading', 'Loading model...', {});
            }
        });

        onStatus('ready', 'Model loaded. Fetching chunks...', {});

        // Process in batches
        const batchSize = 10;
        let hasMore = true;

        while (hasMore) {
            // Fetch chunks needing embeddings
            const formData = new FormData();
            formData.append('action', 'inqyra_get_chunks_for_embedding');
            formData.append('nonce', nonce);
            formData.append('agent_id', agentId);
            formData.append('limit', batchSize);

            const response = await fetch(ajaxUrl, {
                method: 'POST',
                body: formData
            });

            const data = await response.json();

            if (!data.success || !data.data.chunks || data.data.chunks.length === 0) {
                hasMore = false;
                break;
            }

            const chunks = data.data.chunks;
            stats.total += chunks.length;

            for (const chunk of chunks) {
                const currentNum = stats.processed + stats.failed + 1;
                onStatus('processing', `Processing chunk ${currentNum}...`, { chunkId: chunk.id });

                try {
                    // Generate embedding
                    const embedding = await generateEmbedding(chunk.content);

                    // Save to server
                    const saveFormData = new FormData();
                    saveFormData.append('action', 'inqyra_save_embedding');
                    saveFormData.append('nonce', nonce);
                    saveFormData.append('chunk_id', chunk.id);

                    // Send embedding as array
                    embedding.forEach((val, idx) => {
                        saveFormData.append(`embedding[${idx}]`, val);
                    });

                    const saveResponse = await fetch(ajaxUrl, {
                        method: 'POST',
                        body: saveFormData
                    });

                    const saveData = await saveResponse.json();

                    if (saveData.success) {
                        stats.processed++;
                        // Notify success with chunk ID for UI update
                        onStatus('chunk_complete', `Processed: ${stats.processed}`, {
                            chunkId: chunk.id,
                            success: true,
                            stats: { ...stats }
                        });
                    } else {
                        throw new Error(saveData.data?.message || 'Failed to save embedding');
                    }
                } catch (chunkError) {
                    console.error(`Error processing chunk ${chunk.id}:`, chunkError);
                    stats.failed++;

                    // Mark as failed
                    const failFormData = new FormData();
                    failFormData.append('action', 'inqyra_mark_embedding_failed');
                    failFormData.append('nonce', nonce);
                    failFormData.append('chunk_id', chunk.id);

                    await fetch(ajaxUrl, {
                        method: 'POST',
                        body: failFormData
                    });

                    // Notify failure with chunk ID
                    onStatus('chunk_complete', `Processed: ${stats.processed}, Failed: ${stats.failed}`, {
                        chunkId: chunk.id,
                        success: false,
                        stats: { ...stats }
                    });
                }
            }
        }

        // Done
        let finalMessage = `Complete! Processed ${stats.processed} embeddings.`;
        if (stats.failed > 0) {
            finalMessage += ` (${stats.failed} failed)`;
        }
        onStatus('complete', finalMessage, { stats });

        return stats;

    } catch (error) {
        console.error('Embedding error:', error);
        onStatus('error', `Error: ${error.message}`, {});
        return { error: error.message, ...stats };
    } finally {
        isProcessing = false;
    }
}

// Export to window immediately (before any async work)
window.inqyraEmbeddings = {
    initPipeline,
    generateEmbedding,
    processEmbeddings,
    isProcessing: () => isProcessing
};

// Dispatch event when module is ready
window.dispatchEvent(new CustomEvent('inqyra-embeddings-ready'));
