import { loadConfig } from "../config.js";
import log4js from "log4js";
import { sendIPC } from "../electron/ipc.js";
import { DocumentPrinterClient } from "./documentprinterclient.js";
import { startWaiting, stopWaiting } from "../spinner.js";

const config = loadConfig();

const logger = log4js.getLogger("Document Printer Manager");
logger.level = config.logLevel;

export class DocumentPrinterManager {
  constructor(socketClient) {
    this.socketClient = socketClient;
    this.documentPrinterClients = new Map();
    this.documentPrinters = [];
  }

  async reloadDocumentPrinters() {
    startWaiting("Reloading document printers...", logger);
    try {
      this.documentPrinters = await this.socketClient.listObjects({
        objectType: "documentPrinter",
        filter: { host: this.socketClient.id },
      });

      sendIPC("setDocumentPrinters", this.documentPrinters);

      // Remove printer clients that are no longer in the printers list
      const documentPrinterIds = this.documentPrinters.map(
        (documentPrinter) => documentPrinter._id
      );
      for (const [
        documentPrinterId,
        documentPrinterClient,
      ] of this.documentPrinterClients.entries()) {
        if (!documentPrinterIds.includes(documentPrinterId)) {
          // Close the connection before removing
          documentPrinterClient.shouldReconnect = false;
          documentPrinterClient.disconnect();
          this.documentPrinterClients.delete(documentPrinterId);
          logger.info(
            `Removed document printer client for printer ID: ${documentPrinterId}`
          );
        }
      }

      // Add new printer clients for printers not in the documentPrinterClients map
      for (const documentPrinter of this.documentPrinters) {
        const documentPrinterId = documentPrinter._id;
        if (!this.documentPrinterClients.has(documentPrinterId)) {
          const documentPrinterClient = new DocumentPrinterClient(
            documentPrinter,
            this
          );
          this.documentPrinterClients.set(
            documentPrinterId,
            documentPrinterClient
          );
          await documentPrinterClient.reconnect();
          logger.info(
            `Added document printer client for printer ID: ${documentPrinterId}`
          );
        }
      }
      await stopWaiting();
    } catch (error) {
      await stopWaiting();
      logger.error("Failed to update document printers:", error);
      this.documentPrinters = [];
    }
  }

  async handleDocumentPrinterAction(id, action, callback) {
    logger.debug("Running document printer action...", action);
    const documentPrinter = this.getDocumentPrinterClient(id);
    switch (action.type) {
      case "deploy":
        const deployResult = await documentPrinter.deployDocumentJob(
          action.data
        );
        callback(deployResult);
        return;
    }
    callback({ error: "Unknown command." });
  }

  async handleDocumentPrinterUpdate(id, data) {
    logger.debug("Handling document printer update for id:", id);
    const documentPrinter = this.getDocumentPrinterClient(id);
    if (documentPrinter) {
      await documentPrinter.updateDocumentPrinter(data.object);
    }
  }

  getDocumentPrinterClient(documentPrinterId) {
    return this.documentPrinterClients.get(documentPrinterId);
  }

  getAllDocumentPrinterClients() {
    return this.documentPrinterClients.values();
  }

  // Close all printer connections
  closeAllConnections() {
    for (const documentPrinterClient of this.documentPrinterClients.values()) {
      documentPrinterClient.shouldReconnect = false;
      documentPrinterClient.disconnect();
    }
    this.documentPrinterClients.clear();
  }
}
