import { logger } from "../../core/monitoring/logger.js";
import crypto from "crypto";
function getEnv(key, defaultValue) {
  const value = process.env[key];
  if (value === void 0) {
    if (defaultValue !== void 0) return defaultValue;
    throw new Error(`Environment variable ${key} is required`);
  }
  return value;
}
function getOptionalEnv(key) {
  return process.env[key];
}
class OpenAIEmbeddingProvider {
  apiKey;
  model;
  dimensions;
  constructor(model = "text-embedding-ada-002") {
    this.apiKey = process.env["OPENAI_API_KEY"];
    this.model = model;
    this.dimensions = model === "text-embedding-ada-002" ? 1536 : 3072;
  }
  async createEmbedding(text) {
    if (!this.apiKey) {
      throw new Error("OPENAI_API_KEY environment variable is not set");
    }
    try {
      const response = await fetch("https://api.openai.com/v1/embeddings", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Authorization: `Bearer ${this.apiKey}`
        },
        body: JSON.stringify({
          input: text,
          model: this.model
        })
      });
      if (!response.ok) {
        throw new Error(`OpenAI API error: ${response.statusText}`);
      }
      const data = await response.json();
      return data.data[0].embedding;
    } catch (error) {
      logger.error(
        "Failed to create OpenAI embedding",
        error instanceof Error ? error : new Error(String(error))
      );
      throw error;
    }
  }
  getDimensions() {
    return this.dimensions;
  }
  getName() {
    return `OpenAI-${this.model}`;
  }
}
class LocalEmbeddingProvider {
  dimensions;
  vocabulary = /* @__PURE__ */ new Map();
  idf = /* @__PURE__ */ new Map();
  documentCount = 0;
  constructor(dimensions = 384) {
    this.dimensions = dimensions;
  }
  tokenize(text) {
    return text.toLowerCase().replace(/[^\w\s]/g, " ").split(/\s+/).filter((token) => token.length > 2);
  }
  getWordVector(word) {
    const hash = crypto.createHash("sha256").update(word).digest();
    const vector = new Array(this.dimensions).fill(0);
    for (let i = 0; i < Math.min(hash.length, this.dimensions); i++) {
      const value = (hash[i] - 128) / 128;
      vector[i] = value;
    }
    return vector;
  }
  async createEmbedding(text) {
    const tokens = this.tokenize(text);
    const vector = new Array(this.dimensions).fill(0);
    if (tokens.length === 0) {
      return vector;
    }
    const termFreq = /* @__PURE__ */ new Map();
    for (const token of tokens) {
      termFreq.set(token, (termFreq.get(token) || 0) + 1);
    }
    this.documentCount++;
    for (const token of new Set(tokens)) {
      if (!this.vocabulary.has(token)) {
        this.vocabulary.set(token, this.vocabulary.size);
      }
      this.idf.set(token, (this.idf.get(token) || 0) + 1);
    }
    let totalWeight = 0;
    for (const [token, freq] of termFreq.entries()) {
      const tf = freq / tokens.length;
      const docFreq = this.idf.get(token) || 1;
      const idf = Math.log((this.documentCount + 1) / (docFreq + 1));
      const weight = tf * idf;
      const wordVector = this.getWordVector(token);
      for (let i = 0; i < this.dimensions; i++) {
        vector[i] += wordVector[i] * weight;
      }
      totalWeight += weight;
    }
    if (totalWeight > 0) {
      const magnitude = Math.sqrt(
        vector.reduce((sum, val) => sum + val * val, 0)
      );
      if (magnitude > 0) {
        for (let i = 0; i < this.dimensions; i++) {
          vector[i] /= magnitude;
        }
      }
    }
    return vector;
  }
  getDimensions() {
    return this.dimensions;
  }
  getName() {
    return "Local-TFIDF";
  }
}
class HybridEmbeddingProvider {
  openai;
  local;
  useOpenAI;
  constructor(dimensions = 1536) {
    this.openai = new OpenAIEmbeddingProvider();
    this.local = new LocalEmbeddingProvider(dimensions);
    this.useOpenAI = !!process.env["OPENAI_API_KEY"];
    if (!this.useOpenAI) {
      logger.warn("OPENAI_API_KEY not set, using local embeddings");
    }
  }
  async createEmbedding(text) {
    if (this.useOpenAI) {
      try {
        return await this.openai.createEmbedding(text);
      } catch (error) {
        logger.warn(
          "OpenAI embedding failed, falling back to local",
          error instanceof Error ? error : void 0
        );
        this.useOpenAI = false;
      }
    }
    const localEmbedding = await this.local.createEmbedding(text);
    const targetDimensions = this.getDimensions();
    if (localEmbedding.length < targetDimensions) {
      return [
        ...localEmbedding,
        ...new Array(targetDimensions - localEmbedding.length).fill(0)
      ];
    }
    return localEmbedding.slice(0, targetDimensions);
  }
  getDimensions() {
    return this.useOpenAI ? this.openai.getDimensions() : this.local.getDimensions();
  }
  getName() {
    return this.useOpenAI ? this.openai.getName() : `Hybrid-${this.local.getName()}`;
  }
}
function createEmbeddingProvider(type) {
  switch (type) {
    case "openai":
      return new OpenAIEmbeddingProvider();
    case "local":
      return new LocalEmbeddingProvider();
    case "hybrid":
    default:
      return new HybridEmbeddingProvider();
  }
}
export {
  HybridEmbeddingProvider,
  LocalEmbeddingProvider,
  OpenAIEmbeddingProvider,
  createEmbeddingProvider
};
//# sourceMappingURL=embedding-provider.js.map
