const { checkForMigrations } = require("../utils/database");

const WorkspaceChats = {
  tablename: "workspace_chats",
  colsInit: `
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  workspaceId INTEGER NOT NULL,
  prompt TEXT NOT NULL,
  response TEXT NOT NULL,
  include BOOL DEFAULT true,
  user_id INTEGER DEFAULT NULL,
  createdAt TEXT DEFAULT CURRENT_TIMESTAMP,
  lastUpdatedAt TEXT DEFAULT CURRENT_TIMESTAMP,

  FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
  `,
  migrateTable: async function () {
    console.log(
      `\x1b[34m[MIGRATING]\x1b[0m Checking for WorkspaceChats migrations`
    );
    const db = await this.db(false);
    await checkForMigrations(this, db);
  },
  migrations: function () {
    return [
      {
        colName: "user_id",
        execCmd: `ALTER TABLE ${this.tablename} ADD COLUMN user_id INTEGER DEFAULT NULL`,
        doif: false,
      },
    ];
  },
  db: async function (tracing = true) {
    const sqlite3 = require("sqlite3").verbose();
    const { open } = require("sqlite");

    const db = await open({
      filename: `${
        !!process.env.STORAGE_DIR ? `${process.env.STORAGE_DIR}/` : "storage/"
      }anythingllm.db`,
      driver: sqlite3.Database,
    });

    await db.exec(
      `PRAGMA foreign_keys = ON;CREATE TABLE IF NOT EXISTS ${this.tablename} (${this.colsInit})`
    );

    if (tracing) db.on("trace", (sql) => console.log(sql));
    return db;
  },
  new: async function ({ workspaceId, prompt, response = {}, user = null }) {
    const db = await this.db();
    const { id, success, message } = await db
      .run(
        `INSERT INTO ${this.tablename} (workspaceId, prompt, response, user_id) VALUES (?, ?, ?, ?)`,
        [workspaceId, prompt, JSON.stringify(response), user?.id || null]
      )
      .then((res) => {
        return { id: res.lastID, success: true, message: null };
      })
      .catch((error) => {
        return { id: null, success: false, message: error.message };
      });
    if (!success) {
      db.close();
      return { chat: null, message };
    }

    const chat = await db.get(
      `SELECT * FROM ${this.tablename} WHERE id = ${id}`
    );
    db.close();

    return { chat, message: null };
  },
  forWorkspaceByUser: async function (
    workspaceId = null,
    userId = null,
    limit = null
  ) {
    if (!workspaceId || !userId) return [];
    return await this.where(
      `workspaceId = ${workspaceId} AND include = true AND user_id = ${userId}`,
      limit,
      "ORDER BY id ASC"
    );
  },
  forWorkspace: async function (workspaceId = null, limit = null) {
    if (!workspaceId) return [];
    return await this.where(
      `workspaceId = ${workspaceId} AND include = true`,
      limit,
      "ORDER BY id ASC"
    );
  },
  markHistoryInvalid: async function (workspaceId = null, user = null) {
    if (!workspaceId) return;
    const db = await this.db();
    await db.run(
      `UPDATE ${this.tablename} SET include = false WHERE workspaceId = ? ${
        user ? `AND user_id = ${user.id}` : ""
      }`,
      [workspaceId]
    );
    db.close();

    return;
  },
  get: async function (clause = "", limit = null, order = null) {
    const db = await this.db();
    const result = await db
      .get(
        `SELECT * FROM ${this.tablename} WHERE ${clause} ${
          !!order ? order : ""
        } ${!!limit ? `LIMIT ${limit}` : ""}`
      )
      .then((res) => res || null);
    db.close();

    if (!result) return null;
    return result;
  },
  delete: async function (clause = "") {
    const db = await this.db();
    await db.get(`DELETE FROM ${this.tablename} WHERE ${clause}`);
    db.close();

    return true;
  },
  where: async function (clause = "", limit = null, order = null) {
    const db = await this.db();
    const results = await db.all(
      `SELECT * FROM ${this.tablename} ${clause ? `WHERE ${clause}` : ""} ${
        !!order ? order : ""
      } ${!!limit ? `LIMIT ${limit}` : ""}`
    );
    db.close();

    return results;
  },
  count: async function (clause = null) {
    const db = await this.db();
    const { count } = await db.get(
      `SELECT COUNT(*) as count FROM ${this.tablename} ${
        clause ? `WHERE ${clause}` : ""
      } `
    );
    db.close();

    return count;
  },
  whereWithData: async function (clause = "", limit = null, order = null) {
    const { Workspace } = require("./workspace");
    const { User } = require("./user");
    const results = await this.where(clause, limit, order);
    for (const res of results) {
      const workspace = await Workspace.get(`id = ${res.workspaceId}`);
      res.workspace = workspace
        ? { name: workspace.name, slug: workspace.slug }
        : { name: "deleted workspace", slug: null };

      const user = await User.get(`id = ${res.user_id}`);
      res.user = user
        ? { username: user.username }
        : { username: "deleted user" };
    }
    return results;
  },
};

module.exports = { WorkspaceChats };