/**
 * AI Service
 *
 * Main entry point for AI functionality (embeddings + chat completions + task registry).
 */

import { OpenAIProvider } from './providers/openaiProvider.js';
import { GroqProvider, MODELS as GROQ_MODELS } from './providers/groqProvider.js';
import { TaxonomyEmbeddings } from './embeddings/taxonomyEmbeddings.js';
import { cosineSimilarity, findTopMatches } from './embeddings/similarity.js';
import { getRegistry, TASK_IDS, registerAllTasks } from './tasks/index.js';

export { TASK_IDS, GROQ_MODELS, cosineSimilarity, findTopMatches };

let initialized = false;
let initializing = false;
let openaiProvider = null;
let groqProvider = null;
let taxonomyEmbeddings = null;
let logger = console;
let appPool = null;

export async function initialize({ openaiApiKey, groqApiKey, mysqlConnection, pool, logger: customLogger }) {
  if (initialized) return { success: true, message: 'Already initialized' };

  if (initializing) {
    while (initializing) {
      await new Promise((resolve) => setTimeout(resolve, 100));
    }
    return { success: initialized, message: initialized ? 'Initialized' : 'Initialization failed' };
  }

  initializing = true;
  try {
    if (customLogger) logger = customLogger;
    if (!openaiApiKey) throw new Error('OpenAI API key is required');

    logger.info('[AI] Initializing AI service...');
    if (pool) appPool = pool;

    openaiProvider = new OpenAIProvider({ apiKey: openaiApiKey });

    if (groqApiKey) {
      groqProvider = new GroqProvider({ apiKey: groqApiKey });
      logger.info('[AI] Groq provider initialized for chat completions');
    } else {
      logger.warn('[AI] No Groq API key provided - chat completion tasks will not be available');
    }

    taxonomyEmbeddings = new TaxonomyEmbeddings({ provider: openaiProvider, logger });
    const stats = await taxonomyEmbeddings.initialize(mysqlConnection);

    if (groqProvider) registerValidationTasks();

    initialized = true;
    logger.info('[AI] AI service initialized', {
      ...stats,
      groqEnabled: !!groqProvider,
      tasksRegistered: getRegistry().list(),
    });

    return { success: true, message: 'Initialized', stats, groqEnabled: !!groqProvider };
  } catch (error) {
    logger.error('[AI] Initialization failed:', error);
    return { success: false, message: error.message };
  } finally {
    initializing = false;
  }
}

function registerValidationTasks() {
  registerAllTasks(logger);
  logger.info('[AI] Validation tasks registered');
}

export function isReady() {
  return initialized && taxonomyEmbeddings?.isReady();
}

export function startBackgroundCheck(getConnectionFn, intervalMs) {
  if (!initialized || !taxonomyEmbeddings) return;
  taxonomyEmbeddings.startBackgroundCheck(getConnectionFn, intervalMs);
}

function buildProductText(product) {
  const parts = [];
  const name = product.name?.trim();
  const description = product.description?.trim();
  const company = (product.company_name || product.company)?.trim();
  const line = (product.line_name || product.line)?.trim();

  if (name) parts.push(name, name, name);
  if (company) parts.push(company);
  if (line) parts.push(line);
  if (description) {
    const truncated = description.length > 500
      ? description.substring(0, 500) + '...'
      : description;
    parts.push(truncated);
  }

  return parts.join(' ').trim();
}

export async function getProductEmbedding(product) {
  if (!initialized || !openaiProvider) throw new Error('AI service not initialized');

  const text = buildProductText(product);
  if (!text) return { embedding: null, latencyMs: 0 };

  const result = await openaiProvider.embed(text);
  return { embedding: result.embeddings[0], latencyMs: result.latencyMs };
}

export async function getProductEmbeddings(products) {
  if (!initialized || !openaiProvider) throw new Error('AI service not initialized');

  const texts = products.map(buildProductText);
  const validIndices = texts.map((t, i) => t ? i : -1).filter((i) => i >= 0);
  const validTexts = texts.filter((t) => t);

  if (validTexts.length === 0) return { embeddings: [], latencyMs: 0 };

  const result = await openaiProvider.embed(validTexts);
  const embeddings = validIndices.map((originalIndex, resultIndex) => ({
    index: originalIndex,
    embedding: result.embeddings[resultIndex],
  }));
  return { embeddings, latencyMs: result.latencyMs };
}

export function findSimilarTaxonomy(productEmbedding, options = {}) {
  if (!initialized || !taxonomyEmbeddings) throw new Error('AI service not initialized');

  const topCategories = options.topCategories ?? 10;
  const topThemes = options.topThemes ?? 5;
  const topColors = options.topColors ?? 5;

  return {
    categories: taxonomyEmbeddings.findSimilarCategories(productEmbedding, topCategories),
    themes: taxonomyEmbeddings.findSimilarThemes(productEmbedding, topThemes),
    colors: taxonomyEmbeddings.findSimilarColors(productEmbedding, topColors),
  };
}

export async function getSuggestionsForProduct(product, options = {}) {
  const { embedding, latencyMs: embeddingLatency } = await getProductEmbedding(product);

  if (!embedding) {
    return { categories: [], themes: [], colors: [], latencyMs: embeddingLatency };
  }

  const startSearch = Date.now();
  const suggestions = findSimilarTaxonomy(embedding, options);
  const searchLatency = Date.now() - startSearch;

  return {
    ...suggestions,
    latencyMs: embeddingLatency + searchLatency,
    embeddingLatencyMs: embeddingLatency,
    searchLatencyMs: searchLatency,
  };
}

export function getTaxonomyData() {
  if (!initialized || !taxonomyEmbeddings) throw new Error('AI service not initialized');
  return taxonomyEmbeddings.getTaxonomyData();
}

export function getStatus() {
  const registry = getRegistry();
  return {
    initialized,
    ready: isReady(),
    hasOpenAI: !!openaiProvider,
    hasGroq: !!groqProvider,
    hasTaxonomy: !!taxonomyEmbeddings,
    taxonomyStats: taxonomyEmbeddings ? {
      categories: taxonomyEmbeddings.categories?.length || 0,
      themes: taxonomyEmbeddings.themes?.length || 0,
      colors: taxonomyEmbeddings.colors?.length || 0,
    } : null,
    tasks: {
      registered: registry.list(),
      count: registry.size(),
    },
  };
}

export async function runTask(taskId, payload = {}) {
  if (!initialized) throw new Error('AI service not initialized');
  if (!groqProvider) throw new Error('Groq provider not available - chat completion tasks require GROQ_API_KEY');

  const registry = getRegistry();
  return registry.runTask(taskId, {
    ...payload,
    provider: groqProvider,
    pool: payload.pool || appPool,
    logger,
  });
}

export function getGroqProvider() {
  return groqProvider;
}

export function getPool() {
  return appPool;
}

export function hasChatCompletion() {
  return !!groqProvider;
}

export default {
  initialize,
  isReady,
  getStatus,
  startBackgroundCheck,
  getProductEmbedding,
  getProductEmbeddings,
  findSimilarTaxonomy,
  getSuggestionsForProduct,
  getTaxonomyData,
  runTask,
  hasChatCompletion,
  getGroqProvider,
  getPool,
  TASK_IDS,
  GROQ_MODELS,
  cosineSimilarity,
  findTopMatches,
};
