import OpenAI from "openai";

const MODEL = process.env.OPENAI_MODEL || "gpt-4o-mini";

// Appended to every tenant's prompt so the assistant never leaks that answers
// come from uploaded files — a common File Search failure mode.
const GUARDRAIL =
  "\n\nCRITICAL RULES: The visitor has NOT uploaded anything. Never say 'the files you uploaded', 'the documents you provided', 'your files/documents', or refer to uploads, files, PDFs, documents, a knowledge base, or any source. Just answer naturally as a human support agent. For a greeting, say something like 'Hi! How can I help you today?' — never mention files.";

function buildInstructions(systemPrompt) {
  return (systemPrompt || "You are a friendly, professional customer-support assistant.") + GUARDRAIL;
}

// One OpenAI client per API key. Each tenant may bring their own key; if they
// haven't, we fall back to the platform key from the environment.
const clients = new Map();
export function getClient(apiKey) {
  const key = apiKey || process.env.OPENAI_API_KEY || "";
  if (!clients.has(key)) clients.set(key, new OpenAI({ apiKey: key }));
  return clients.get(key);
}

// Backwards-compatible default client (platform key).
export const client = getClient();

/**
 * Ask a question against a vector store using the Responses API + file_search.
 * @param {object} opts { client, message, vectorStoreId, systemPrompt, previousResponseId }
 */
export async function askKnowledgeBase({ client, message, vectorStoreId, systemPrompt, previousResponseId }) {
  if (!vectorStoreId) throw new Error("This assistant has no knowledge base yet.");
  const request = {
    model: MODEL,
    input: message,
    tools: [{ type: "file_search", vector_store_ids: [vectorStoreId] }],
    instructions: buildInstructions(systemPrompt),
  };
  if (previousResponseId) request.previous_response_id = previousResponseId;
  const response = await client.responses.create(request);
  return { text: response.output_text?.trim() || "Sorry, I couldn't generate a reply.", responseId: response.id };
}

/**
 * Streaming variant.
 * @param {object} opts { client, message, vectorStoreId, systemPrompt, previousResponseId }
 * @param {object} cb   { onDelta, onSearching?, onDone }
 */
export async function streamKnowledgeBase({ client, message, vectorStoreId, systemPrompt, previousResponseId }, cb) {
  if (!vectorStoreId) throw new Error("This assistant has no knowledge base yet.");
  const request = {
    model: MODEL,
    input: message,
    tools: [{ type: "file_search", vector_store_ids: [vectorStoreId] }],
    stream: true,
    instructions: buildInstructions(systemPrompt),
  };
  if (previousResponseId) request.previous_response_id = previousResponseId;

  const stream = await client.responses.create(request);
  let responseId = previousResponseId || "";
  for await (const event of stream) {
    switch (event.type) {
      case "response.created": responseId = event.response?.id || responseId; break;
      case "response.file_search_call.searching":
      case "response.file_search_call.in_progress": cb.onSearching?.(); break;
      case "response.output_text.delta": if (event.delta) cb.onDelta(event.delta); break;
      case "response.completed": responseId = event.response?.id || responseId; break;
      case "response.failed": throw new Error(event.response?.error?.message || "response failed");
    }
  }
  cb.onDone(responseId);
}
