import { app, ipcMain } from "electron";
import log from "electron-log/main";
import { autoUpdater } from "electron-updater";
import path from "path";
import ipcTypes from "../../util/ipcTypes.json";
import ImportJob from "../decoder/decoder";
import store from "../store/store";
import { StartWatcher, StopWatcher } from "../watcher/watcher";
import {
  SettingEmsOutFilePathGet,
  SettingEmsOutFilePathSet,
  SettingsPaintScaleInputConfigsGet,
  SettingsPaintScaleInputConfigsSet,
  SettingsPaintScaleInputPathSet,
  SettingsPaintScaleOutputConfigsGet,
  SettingsPaintScaleOutputConfigsSet,
  SettingsPaintScaleOutputPathSet,
  SettingsPpcFilePathGet,
  SettingsPpcFilePathSet,
  SettingsWatchedFilePathsAdd,
  SettingsWatchedFilePathsGet,
  SettingsWatchedFilePathsRemove,
  SettingsWatcherPollingGet,
  SettingsWatcherPollingSet,
} from "./ipcMainHandler.settings";
import {
  ipcMainHandleAuthStateChanged,
  ipMainHandleResetPassword,
} from "./ipcMainHandler.user";
import cron from "node-cron";
import { PaintScaleConfig, PaintScaleType } from "../../util/types/paintScale";
import { ppgInputHandler, ppgOutputHandler } from "./paintScaleHandlers/PPG";

const initializeCronTasks = async () => {
  try {
    // Fetch input and output configurations
    const inputConfigs = await SettingsPaintScaleInputConfigsGet();
    const outputConfigs = await SettingsPaintScaleOutputConfigsGet();

    // Start input cron tasks
    await handlePaintScaleInputCron(inputConfigs);
    log.info("Initialized input cron tasks on app startup");

    // Start output cron tasks
    await handlePaintScaleOutputCron(outputConfigs);
    log.info("Initialized output cron tasks on app startup");
  } catch (error) {
    log.error("Error initializing cron tasks on app startup:", error);
  }
};

// Log all IPC messages and their payloads
const logIpcMessages = (): void => {
  Object.keys(ipcTypes.toMain).forEach((key) => {
    const messageType = ipcTypes.toMain[key];
    const originalHandler = ipcMain.listeners(messageType)?.[0];
    if (originalHandler) {
      ipcMain.removeAllListeners(messageType);
    }
    ipcMain.on(messageType, (event, payload) => {
      log.info(
        `%c[IPC Main]%c${messageType}`,
        "color: red",
        "color: green",
        payload,
      );
      if (originalHandler) {
        originalHandler(event, payload);
      }
    });
  });
};

// Input handler map
const inputTypeHandlers: Partial<
  Record<PaintScaleType, (config: PaintScaleConfig) => Promise<void>>
> = {
  [PaintScaleType.PPG]: ppgInputHandler,
  // Add other input type handlers as needed
};

// Output handler map
const outputTypeHandlers: Partial<
  Record<PaintScaleType, (config: PaintScaleConfig) => Promise<void>>
> = {
  [PaintScaleType.PPG]: ppgOutputHandler,
  // Add other output type handlers as needed
};

// Default handler for unsupported types
const defaultHandler = async (config: PaintScaleConfig) => {
  log.debug(
    `No handler defined for type ${config.type} in config ${config.id}`,
  );
};

// Input cron job management
let inputCronTasks: { [id: string]: cron.ScheduledTask } = {};

const handlePaintScaleInputCron = async (configs: PaintScaleConfig[]) => {
  Object.values(inputCronTasks).forEach((task) => task.stop());
  inputCronTasks = {};

  const validConfigs = configs.filter(
    (config) => config.path && config.path.trim() !== "",
  );

  validConfigs.forEach((config) => {
    const cronExpression = `*/${config.pollingInterval} * * * *`;
    inputCronTasks[config.id] = cron.schedule(cronExpression, async () => {
      const handler = inputTypeHandlers[config.type] || defaultHandler;
      await handler(config);
    });
    log.info(
      `Started input cron task for config ${config.id} (type: ${config.type}) with interval ${config.pollingInterval}m`,
    );
  });
};

// Output cron job management
let outputCronTasks: { [id: string]: cron.ScheduledTask } = {};

const handlePaintScaleOutputCron = async (configs: PaintScaleConfig[]) => {
  Object.values(outputCronTasks).forEach((task) => task.stop());
  outputCronTasks = {};

  const validConfigs = configs.filter(
    (config) => config.path && config.path.trim() !== "",
  );

  validConfigs.forEach((config) => {
    const cronExpression = `*/${config.pollingInterval} * * * *`;
    outputCronTasks[config.id] = cron.schedule(cronExpression, async () => {
      const handler = outputTypeHandlers[config.type] || defaultHandler;
      await handler(config);
    });
    log.info(
      `Started output cron task for config ${config.id} (type: ${config.type}) with interval ${config.pollingInterval}m`,
    );
  });
};

// Existing IPC handlers...

ipcMain.on(ipcTypes.toMain.test, () =>
  console.log("** Verify that ipcMain is loaded and working."),
);

// Auth handler
ipcMain.on(ipcTypes.toMain.authStateChanged, ipcMainHandleAuthStateChanged);
ipcMain.on(ipcTypes.toMain.user.resetPassword, ipMainHandleResetPassword);

// Add debug handlers if in development
if (import.meta.env.DEV) {
  log.debug("[IPC Debug Functions] Adding Debug Handlers");

  ipcMain.on(ipcTypes.toMain.debug.decodeEstimate, async (): Promise<void> => {
    const relativeEmsFilepath = `_reference/ems/MPI_1/3698420.ENV`;
    const rootDir = app.getAppPath();
    const absoluteFilepath = path.join(rootDir, relativeEmsFilepath);

    log.debug("[IPC Debug Function] Decode test Estimate", absoluteFilepath);
    await ImportJob(absoluteFilepath);

    const job2 = `/Users/pfic/Downloads/12285264/2285264.ENV`;
    const job3 = `/Users/pfic/Downloads/14033376/4033376.ENV`;
    await ImportJob(job2);
    await ImportJob(job3);
  });
}

// Settings Handlers
ipcMain.handle(
  ipcTypes.toMain.settings.filepaths.get,
  SettingsWatchedFilePathsGet,
);
ipcMain.handle(
  ipcTypes.toMain.settings.filepaths.add,
  SettingsWatchedFilePathsAdd,
);
ipcMain.handle(
  ipcTypes.toMain.settings.filepaths.remove,
  SettingsWatchedFilePathsRemove,
);
ipcMain.handle(
  ipcTypes.toMain.settings.watcher.getpolling,
  SettingsWatcherPollingGet,
);
ipcMain.handle(
  ipcTypes.toMain.settings.watcher.setpolling,
  SettingsWatcherPollingSet,
);

ipcMain.handle(ipcTypes.toMain.settings.getPpcFilePath, SettingsPpcFilePathGet);
ipcMain.handle(ipcTypes.toMain.settings.setPpcFilePath, SettingsPpcFilePathSet);
ipcMain.handle(
  ipcTypes.toMain.settings.getEmsOutFilePath,
  SettingEmsOutFilePathGet,
);
ipcMain.handle(
  ipcTypes.toMain.settings.setEmsOutFilePath,
  SettingEmsOutFilePathSet,
);

// Paint Scale Input Settings Handlers
ipcMain.handle(
  ipcTypes.toMain.settings.paintScale.getInputConfigs,
  SettingsPaintScaleInputConfigsGet,
);
ipcMain.handle(
  ipcTypes.toMain.settings.paintScale.setInputConfigs,
  SettingsPaintScaleInputConfigsSet,
);
ipcMain.handle(
  ipcTypes.toMain.settings.paintScale.setInputPath,
  SettingsPaintScaleInputPathSet,
);

// Paint Scale Output Settings Handlers
ipcMain.handle(
  ipcTypes.toMain.settings.paintScale.getOutputConfigs,
  SettingsPaintScaleOutputConfigsGet,
);
ipcMain.handle(
  ipcTypes.toMain.settings.paintScale.setOutputConfigs,
  SettingsPaintScaleOutputConfigsSet,
);
ipcMain.handle(
  ipcTypes.toMain.settings.paintScale.setOutputPath,
  SettingsPaintScaleOutputPathSet,
);

// IPC handlers for updating paint scale cron
ipcMain.on(
  ipcTypes.toMain.settings.paintScale.updateInputCron,
  (_event, configs: PaintScaleConfig[]) => {
    handlePaintScaleInputCron(configs).catch((error) => {
      log.error(`Error handling paint scale input cron for configs: ${error}`);
    });
  },
);

ipcMain.on(
  ipcTypes.toMain.settings.paintScale.updateOutputCron,
  (_event, configs: PaintScaleConfig[]) => {
    handlePaintScaleOutputCron(configs).catch((error) => {
      log.error(`Error handling paint scale output cron for configs: ${error}`);
    });
  },
);

ipcMain.handle(ipcTypes.toMain.user.getActiveShop, () => {
  return store.get("app.bodyshop.shopname");
});

// Watcher Handlers
ipcMain.on(ipcTypes.toMain.watcher.start, () => {
  StartWatcher().catch((error) => {
    log.error("Error starting watcher:", error);
  });
});

ipcMain.on(ipcTypes.toMain.watcher.stop, () => {
  StopWatcher().catch((error) => {
    log.error("Error stopping watcher:", error);
  });
});

ipcMain.on(ipcTypes.toMain.updates.download, () => {
  log.info("Download update requested from renderer.");
  autoUpdater.downloadUpdate().catch((error) => {
    log.error("Error downloading update:", error);
  });
});

export { initializeCronTasks };

logIpcMessages();
