import { ipcMain, app, BrowserWindow } from "electron";
import { createReadStream, statSync } from "fs";
import { getInstalledPackages } from "./tea-dir";
import { readSessionData, writeSessionData } from "./auth";
import type { Packages, Session } from "../../src/libs/types";
import * as log from "electron-log";
import { post } from "./v1-client";
import { deepReadDir, deletePackageFolder } from "./tea-dir";
import path from "path";

import { installPackage, openTerminal, syncPantry } from "./cli";

import initializeTeaCli from "./initialize";

import { getUpdater } from "./auto-updater";
import fetch from "node-fetch";

import { loadPackageCache, writePackageCache } from "./package";
let teaProtocolPath = ""; // this should be empty string

export const setProtocolPath = (path: string) => {
	teaProtocolPath = path;
};

export default function initializeHandlers() {
	ipcMain.handle("get-installed-packages", async () => {
		try {
			log.info("getting installed packages");
			const pkgs = await getInstalledPackages();
			log.info(`got installed packages: ${pkgs.length}`);
			return pkgs;
		} catch (error) {
			log.error(error);
			return [];
		}
	});

	ipcMain.handle("get-session", async () => {
		try {
			log.info("getting session");
			const session = await readSessionData();
			log.debug(session ? "found session data" : "no session data found");
			return session;
		} catch (error) {
			log.error(error);
			return {};
		}
	});

	ipcMain.handle("update-session", async (_, data) => {
		try {
			log.info("updating session data with", data); // rm this
			await writeSessionData(data as Session);
		} catch (error) {
			log.error(error);
		}
	});

	ipcMain.handle("install-package", async (_, data) => {
		try {
			log.info("installing package:", data.full_name);
			const result = await installPackage(data.full_name);
			return result;
		} catch (error) {
			log.error(error);
			return error;
		}
	});

	ipcMain.handle("sync-pantry", async () => {
		try {
			return await syncPantry();
		} catch (error) {
			log.error(error);
			return error;
		}
	});

	ipcMain.handle("open-terminal", async (_, data) => {
		const { cmd } = data as { cmd: string };
		try {
			// TODO: detect if mac or linux
			// current openTerminal is only design for Mac
			log.info("open terminal w/ cmd:", cmd);
			await openTerminal(cmd);
		} catch (error) {
			log.error(error);
		}
	});

	ipcMain.handle("relaunch", async () => {
		try {
			const autoUpdater = getUpdater();
			await autoUpdater.quitAndInstall();
		} catch (error) {
			log.error(error);
		}
	});

	ipcMain.handle("get-protocol-path", async () => {
		const path = teaProtocolPath;
		teaProtocolPath = "";
		return path;
	});

	ipcMain.handle("submit-logs", async () => {
		try {
			log.info("syncing logs");
			const logDir = path.join(app.getPath("home"), "Library/Logs/tea");
			// ['/Users/neil/Library/Logs/tea/main.log']
			const logFiles = await deepReadDir({ dir: logDir });
			let deviceId = "";
			const files = logFiles.map((p) => {
				const paths = p.split("/");
				deviceId = paths[2]; // temp hack use developers username instead of gui_id
				return paths.pop();
			});

			const signedUrls = await post<{ [key: string]: string }>(`/gui/${deviceId}/sync-log-files`, {
				files
			});
			if (signedUrls) {
				for (const key in signedUrls) {
					const fileIndex = files.indexOf(key);
					const filePath = logFiles[fileIndex];
					if (filePath) {
						const payload = createReadStream(filePath);
						const response = await fetch(signedUrls[key], {
							method: "PUT",
							body: payload,
							headers: {
								"Content-Length": statSync(filePath).size.toString()
							}
						});
						log.info("uploading log:", key, response.status);
					}
				}
			}

			return `log files(${logFiles.length}) has been uploaded to S3 logs/${deviceId}`;
		} catch (error) {
			log.error(error);
			return error.message;
		}
	});

	ipcMain.handle("set-badge-count", async (_, { count }) => {
		console.log("set badge count:", count);
		if (count) {
			app.dock.setBadge(count.toString());
		} else {
			app.dock.setBadge("");
		}
	});

	ipcMain.handle(
		"delete-package",
		async (_, { fullName, version }: { fullName: string; version: string }) => {
			let error = "";
			try {
				log.info("deleting package:", fullName);
				await deletePackageFolder(fullName, version);
			} catch (e) {
				log.error(e);
				error = e.message;
			}
			return error;
		}
	);

	ipcMain.handle("write-package-cache", async (_, data) => {
		try {
			await writePackageCache(data as Packages);
		} catch (error) {
			log.error(error);
		}
	});

	ipcMain.handle("load-package-cache", async () => {
		try {
			return await loadPackageCache();
		} catch (error) {
			log.error(error);
			return { version: "1", packages: {} };
		}
	});

	ipcMain.handle("get-tea-version", async () => {
		try {
			log.info("installing tea cli");
			const version = await initializeTeaCli();
			if (!version) {
				throw new Error("failed to install tea cli");
			}

			return { version, message: "" };
		} catch (error) {
			log.error(error);
			return { version: "", message: error.message };
		}
	});

	ipcMain.handle("topbar-double-click", async (event: Electron.IpcMainInvokeEvent) => {
		const mainWindow = BrowserWindow.fromWebContents(event.sender);
		if (mainWindow) {
			mainWindow.isMaximized() ? mainWindow.unmaximize() : mainWindow.maximize();
		}
	});
}
