import net from "node:net";
import { eq } from "drizzle-orm";
import { db } from "../db/db.controller.js";
import { dockDoorScanners } from "../db/schema/dockdoor.schema.js";
import { printerData } from "../db/schema/printers.schema.js";
import loadUnit from "../dockdoorScanning/dockdoor.loadUnits.js";
import { createLogger } from "../logger/logger.controller.js";
import { delay } from "../utils/delay.utils.js";
import { returnFunc } from "../utils/returnHelper.utils.js";
import { tryCatch } from "../utils/trycatch.utils.js";
import { type PrinterData, printerListen } from "./tcp.printerListener.js";

let tcpServer: net.Server;
const tcpSockets: Set<net.Socket> = new Set();
export let isServerRunning = false;

const port = parseInt(process.env.TCP_PORT ?? "2222", 10);

// This is the parser for zebra scanners
const parseTcpAlert = (input: string) => {
	// guard
	const colonIndex = input.indexOf(":");
	if (colonIndex === -1) return null;

	const condition = input.slice(0, colonIndex).trim();
	const rest = input.slice(colonIndex + 1).trim();

	// extract all [ ... ] blocks from rest
	const matches = [...rest.matchAll(/\[(.*?)\]/g)];

	const date = matches[0]?.[1] ?? "";
	const name = matches[1]?.[1] ?? "";

	// message = everything before first "["
	const bracketIndex = rest.indexOf("[");
	const message =
		bracketIndex !== -1 ? rest.slice(0, bracketIndex).trim() : rest;

	return {
		condition,
		message,
		date,
		name,
	};
};
const log = createLogger({ module: "tcp", submodule: "create_server" });
export const startTCPServer = async () => {
	tcpServer = net.createServer(async (socket) => {
		tcpSockets.add(socket);
		socket.on("data", async (data: Buffer) => {
			const parseData = data.toString("utf-8").trimEnd();

			// check where the data came from then we do something.

			const ip = socket.remoteAddress ?? "127.0.0.1";
			const { data: printer, error: pError } = await tryCatch(
				db
					.select()
					.from(printerData)
					.where(eq(printerData.ipAddress, ip.replace("::ffff:", ""))),
			);
			if (pError) {
				log.error(
					{ stack: pError },
					"There was an error getting printer data for tcp check",
				);
				return;
			}

			if (printer?.length) {
				const printerData = {
					...parseTcpAlert(parseData),
					ip,
					printerSN: printer[0]?.printerSN,
					name: printer[0]?.name,
				};

				printerListen(printerData as PrinterData);
			}

			// check if its a dock door scanner
			const dockdoorScanners = await db.select().from(dockDoorScanners);

			if (dockdoorScanners.some((s) => s.ip === ip.replace("::ffff:", ""))) {
				console.log("dock door logic");

				const currentDock = dockdoorScanners.filter(
					(s) => s.ip === ip.replace("::ffff:", ""),
				);

				// send the data + dock scan over
				loadUnit({
					dockId: currentDock[0]?.dockId ?? "0",
					sscc: data.toString(),
				});
			}
		});

		socket.on("end", () => {
			log.debug({}, "Client disconnected");
			// just in case we dont fully disconnect
			setTimeout(() => {
				if (!socket.destroyed) {
					socket.destroy();
				}
			}, 1000);
			tcpSockets.delete(socket);
		});

		socket.on("error", (err: Error) => {
			log.error({ stack: err }, `Socket error:", ${err}`);
			// just in case we dont fully disconnect
			setTimeout(() => {
				if (!socket.destroyed) {
					socket.destroy();
				}
			}, 1000);
			tcpSockets.delete(socket);
		});
	});

	tcpServer.listen(port, () => {
		log.info({}, `TCP Server listening on port ${port}`);
	});

	isServerRunning = true;
	return returnFunc({
		success: true,
		level: "info",
		module: "tcp",
		subModule: "create_server",
		message: "TCP server started.",
		data: [],
		notify: false,
		room: "",
	});
};

export const stopTCPServer = async () => {
	if (!isServerRunning)
		return { success: false, message: "Server is not running" };
	for (const socket of tcpSockets) {
		socket.destroy();
	}
	tcpSockets.clear();
	tcpServer.close(() => {
		log.info({}, "TCP Server stopped");
	});
	isServerRunning = false;
	return returnFunc({
		success: true,
		level: "info",
		module: "tcp",
		subModule: "create_server",
		message: "TCP server stopped.",
		data: [],
		notify: false,
		room: "",
	});
};

export const restartTCPServer = async () => {
	if (!isServerRunning) {
		startTCPServer();
		return returnFunc({
			success: false,
			level: "warn",
			module: "tcp",
			subModule: "create_server",
			message: "Server is not running will try to start it",
			data: [],
			notify: false,
			room: "",
		});
	} else {
		for (const socket of tcpSockets) {
			socket.destroy();
		}
		tcpSockets.clear();
		tcpServer.close(() => {
			log.info({}, "TCP Server stopped");
		});
		isServerRunning = false;

		await delay(1500);

		startTCPServer();
	}

	return returnFunc({
		success: true,
		level: "info",
		module: "tcp",
		subModule: "create_server",
		message: "TCP server has been restarted.",
		data: [],
		notify: false,
		room: "",
	});
};
