import chokidar, { FSWatcher } from "chokidar";
import { BrowserWindow, Notification } from "electron";
import log from "electron-log/main";
import fs from "fs";
import path from "path";
import errorTypeCheck from "../../util/errorTypeCheck";
import ipcTypes from "../../util/ipcTypes.json";
import ImportJob from "../decoder/decoder";
import store from "../store/store";
let watcher: FSWatcher | null;

async function StartWatcher(): Promise<boolean> {
  const filePaths: string[] = store.get("settings.filepaths") || [];

  if (filePaths.length === 0) {
    new Notification({
      //TODO: Add Translations
      title: "Watcher cannot start",
      body: "Please set the appropriate file paths and try again.",
    }).show();
    log.warn("Cannot start watcher. No file paths set.");
    return false;
  }

  if (watcher) {
    try {
      log.info("Trying to close watcher - it already existed.");
      await watcher.close();

      log.info("Watcher closed successfully!");
    } catch (error) {
      log.error("Error trying to close Watcher.", error);
    }
  }

  const pollingSettings =
    (store.get("settings.polling") as {
      enabled?: boolean;
      interval?: number;
    }) || {};

  watcher = chokidar.watch(filePaths, {
    ignored: (filepath, stats) => {
      const p = path.parse(filepath);
      return !stats?.isFile() && p.ext !== "" && p.ext.toUpperCase() !== ".ENV"; //Only watch for .ENV files.
    },
    usePolling: pollingSettings.enabled || false,
    interval: pollingSettings.interval || 30000,
    persistent: true,
    ignoreInitial: true,
    awaitWriteFinish: {
      pollInterval: 500,
      stabilityThreshold: 2000,
    },
  });

  watcher
    .on("add", async function (path) {
      console.log("File", path, "has been added");
      HandleNewFile(path);
    })
    // .on("addDir", function (path) {
    //   console.log("Directory", path, "has been added");
    // })
    .on("change", async function (path) {
      console.log("File", path, "has been changed");
      HandleNewFile(path);
    })
    // .on("unlink", function (path) {
    //   console.log("File", path, "has been removed");
    // })
    // .on("unlinkDir", function (path) {
    //   console.log("Directory", path, "has been removed");
    // })
    .on("error", function (error) {
      log.error("Error in Watcher", errorTypeCheck(error));
      // mainWindow.webContents.send(
      //   ipcTypes.toRenderer.watcher.error,
      //   errorTypeCheck(error)
      // );
    })
    .on("ready", onWatcherReady);
  // .on("raw", function (event, path, details) {
  //   // This event should be triggered everytime something happens.
  //   // console.log("Raw event info:", event, path, details);
  // });

  return true;
}

function removeWatcherPath(path: string): void {
  if (watcher) {
    watcher.unwatch(path);
    log.debug(`Stopped watching path: ${path}`);
  }
}

function addWatcherPath(path: string | string[]): void {
  if (watcher) {
    watcher.add(path);
    log.debug(`Started watching path: ${path}`);
  }
}

function onWatcherReady(): void {
  if (watcher) {
    const mainWindow = BrowserWindow.getAllWindows()[0]; //TODO: Filter to only main window once a proper key has been set.
    new Notification({
      title: "Watcher Started",
      body: "Newly exported estimates will be automatically uploaded.",
    }).show();
    log.info("Confirmed watched paths:", watcher.getWatched());
    mainWindow.webContents.send(ipcTypes.toRenderer.watcher.started);
  }
}

async function StopWatcher(): Promise<boolean> {
  const mainWindow = BrowserWindow.getAllWindows()[0]; //TODO: Filter to only main window once a proper key has been set.

  if (watcher) {
    await watcher.close();
    log.info("Watcher stopped.");
    mainWindow.webContents.send(ipcTypes.toRenderer.watcher.stopped);

    new Notification({
      title: "Watcher Stopped",
      body: "Estimates will not be automatically uploaded.",
    }).show();
    return true;
  }
  return false;
}

async function HandleNewFile(path): Promise<void> {
  log.log("Received a new file", path);
  await ImportJob(path);
}

function GetAllEnvFiles(): string[] {
  const directories = store.get("settings.filepaths") as string[];
  const files: string[] = [];
  directories.forEach((directory) => {
    try {
      const envFiles = fs
        .readdirSync(directory)
        .filter((file: string) => file.toLowerCase().endsWith(".env"));
      envFiles.forEach((file) => {
        const fullPath = path.join(directory, file);
        files.push(fullPath);
      });
    } catch (error) {
      log.error(`Failed to read directory ${directory}:`, error);
      throw error;
    }
  });
  return files;
}

export {
  addWatcherPath,
  GetAllEnvFiles,
  removeWatcherPath,
  StartWatcher,
  StopWatcher,
  watcher,
};
