const { Worker } = require("worker_threads");
const TaskList = require("../global/task-list");
const { sendUpdate } = require("../ws");
const taskstate = require("../logging/taskstate");
const db = require("../db");

class TaskManager {
  constructor() {
    this.tasks = {};
    this.taskList = TaskList;
    this.emitTaskList();
  }

  addTask({ task, onComplete, onError, onExit }) {
    if (this.tasks[task.name]) {
      console.log(`Task ${task.name} already exists.`);
      return false;
    }

    const worker = new Worker(task.path);

    worker.on("message", (message) => {
      if (message.type === "log") {
        // Handle console.log messages
        console.log(`[Worker Log]: ${message.message}`);
      }
      if (message.status === "complete" && onComplete) {
        onComplete();
      }
      if (message.status === "error" && onError) {
        onError(new Error(message.message));
      }
      delete this.tasks[task.name];
    });

    worker.on("error", (error) => {
      if (onError) {
        onError(error);
      }
      console.error(`Error from ${task.name}:`, error);
      delete this.tasks[task.name];
    });

    worker.on("exit", async (code) => {
      if (code !== 0) {
        console.error(`Worker ${task.name} stopped with exit code ${code}`);
      }
      if (code !== 0 && onExit) {
        onExit();
      }
      delete this.tasks[task.name];
      try {
        await db.query(
          `UPDATE jf_logging SET "Result"='${taskstate.FAILED}' WHERE "Result"='${taskstate.RUNNING}' AND "Name"='${task.name}'`
        );
      } catch (error) {
        console.log("Clear Running Tasks Error: " + error);
      }
    });

    this.tasks[task.name] = { worker };
    return true;
  }

  startTask(task, triggerType) {
    const taskExists = this.tasks[task.name];
    if (!taskExists) {
      console.log(`Task ${task.name} does not exist.`);
      return;
    }
    taskExists.worker.postMessage({ command: "start", triggertype: triggerType });
  }

  stopTask(task) {
    const taskExists = this.tasks[task.name];
    if (!taskExists) {
      console.log(`Task ${task.name} does not exist.`);
      return;
    }

    taskExists.worker.terminate();
    delete this.tasks[task.name];
  }

  isTaskRunning(taskName) {
    return !!this.tasks[taskName];
  }

  emitTaskList() {
    let emitTasks = setInterval(async () => {
      const taskList = Object.keys(this.taskList).map((key) => {
        return { task: key, name: this.taskList[key].name, running: this.isTaskRunning(this.taskList[key].name) };
      });
      sendUpdate("task-list", taskList);
    }, 1000);
  }
}

module.exports = TaskManager;
