const { v4: uuidv4 } = require("uuid");
const { OpenAi } = require("../openAi");
const { WorkspaceChats } = require("../../models/workspaceChats");
const { resetMemory } = require("./commands/reset");
const moment = require("moment");
const { getVectorDbClass } = require("../helpers");

function convertToChatHistory(history = []) {
  const formattedHistory = [];
  history.forEach((history) => {
    const { prompt, response, createdAt } = history;
    const data = JSON.parse(response);
    formattedHistory.push([
      {
        role: "user",
        content: prompt,
        sentAt: moment(createdAt).unix(),
      },
      {
        role: "assistant",
        content: data.text,
        sources: data.sources || [],
        sentAt: moment(createdAt).unix(),
      },
    ]);
  });

  return formattedHistory.flat();
}

function convertToPromptHistory(history = []) {
  const formattedHistory = [];
  history.forEach((history) => {
    const { prompt, response } = history;
    const data = JSON.parse(response);
    formattedHistory.push([
      { role: "user", content: prompt },
      { role: "assistant", content: data.text },
    ]);
  });
  return formattedHistory.flat();
}

const VALID_COMMANDS = {
  "/reset": resetMemory,
};

function grepCommand(message) {
  const availableCommands = Object.keys(VALID_COMMANDS);

  for (let i = 0; i < availableCommands.length; i++) {
    const cmd = availableCommands[i];
    const re = new RegExp(`^(${cmd})`, "i");
    if (re.test(message)) {
      return cmd;
    }
  }

  return null;
}

async function chatWithWorkspace(workspace, message, chatMode = "query") {
  const uuid = uuidv4();
  const openai = new OpenAi();
  const VectorDb = getVectorDbClass();
  const command = grepCommand(message);

  if (!!command && Object.keys(VALID_COMMANDS).includes(command)) {
    return await VALID_COMMANDS[command](workspace, message, uuid);
  }

  const { safe, reasons = [] } = await openai.isSafe(message);
  if (!safe) {
    return {
      id: uuid,
      type: "abort",
      textResponse: null,
      sources: [],
      close: true,
      error: `This message was moderated and will not be allowed. Violations for ${reasons.join(
        ", "
      )} found.`,
    };
  }

  const hasVectorizedSpace = await VectorDb.hasNamespace(workspace.slug);
  if (!hasVectorizedSpace) {
    const rawHistory = await WorkspaceChats.forWorkspace(workspace.id);
    const chatHistory = convertToPromptHistory(rawHistory);
    const response = await openai.sendChat(chatHistory, message);
    const data = { text: response, sources: [], type: "chat" };

    await WorkspaceChats.new({
      workspaceId: workspace.id,
      prompt: message,
      response: data,
    });
    return {
      id: uuid,
      type: "textResponse",
      textResponse: response,
      sources: [],
      close: true,
      error: null,
    };
  } else {
    const {
      response,
      sources,
      message: error,
    } = await VectorDb[chatMode]({ namespace: workspace.slug, input: message });
    if (!response) {
      return {
        id: uuid,
        type: "abort",
        textResponse: null,
        sources: [],
        close: true,
        error,
      };
    }

    const data = { text: response, sources, type: chatMode };
    await WorkspaceChats.new({
      workspaceId: workspace.id,
      prompt: message,
      response: data,
    });
    return {
      id: uuid,
      type: "textResponse",
      textResponse: response,
      sources,
      close: true,
      error,
    };
  }
}
module.exports = {
  convertToChatHistory,
  chatWithWorkspace,
};