import net from "net";
import { OpenAPIHono } from "@hono/zod-openapi";
import { createLog } from "../logger/logger.js";

import startTCP from "./route/startServer.js";
import stopTCP from "./route/stopServer.js";
import restartTCP from "./route/restartServer.js";
import { db } from "../../../database/dbclient.js";
import { settings } from "../../../database/schema/settings.js";
import { eq } from "drizzle-orm";
import { postLabelData } from "../ocme/controller/postRunningNr.js";
import { tryCatch } from "../../globalUtils/tryCatch.js";
import { serverSettings } from "../server/controller/settings/getSettings.js";

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

/**
 * add in proper logging
 */
// const tcpPort = await db
//     .select()
//     .from(settings)
//     .where(eq(settings.name, "tcpPort"));

const app = new OpenAPIHono();

export const startTCPServer = () => {
    const tcpPort = serverSettings.filter((n) => n.name === "tcpPort");
    if (isServerRunning)
        return { success: false, message: "Server is already running" };

    tcpServer = net.createServer(async (socket) => {
        createLog("debug", "tcp", "tcp", "Client connected");

        // const { data: setting, error: settingError } = await tryCatch(
        //     db.select().from(settings)
        // );
        // if (settingError) {
        //     return {
        //         success: false,
        //         message: "Error getting settings",
        //         data: [],
        //     };
        // }

        const settingCheck = serverSettings.filter(
            (newData) => newData.name === "ocmeService"
        );

        tcpSockets.add(socket);
        socket.on("data", (data: Buffer) => {
            const parseData = data.toString("utf-8").trimEnd().split(" ");
            // hb from the scanners
            if (parseData[0] === "HB") {
                createLog(
                    "debug",
                    "tcp",
                    "tcp",
                    `Received:", ${data.toString()}`
                );
                return;
            }

            // alert from the printers
            if (parseData[0] === "ALERT:" || parseData[0] === "ALERT") {
                return;
            }

            // from the wrapper send the data
            const ocmeSetting: any = settingCheck;
            if (ocmeSetting[0]?.value === "1") {
                postLabelData(parseData);
            }
        });

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

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

    tcpServer.listen(tcpPort[0]?.value ?? 2222, () => {
        createLog(
            "info",
            "lst",
            "tcp",
            `TCP Server listening on port ${tcpPort[0]?.value ?? 2222}`
        );
    });

    isServerRunning = true;
    return { success: true, message: "TCP Server started" };
};

// Function to stop the TCP server
export const stopTCPServer = () => {
    if (!isServerRunning)
        return { success: false, message: "Server is not running" };
    for (const socket of tcpSockets) {
        socket.destroy();
    }
    tcpSockets.clear();
    tcpServer.close(() => {
        createLog("info", "tcp", "tcp", "TCP Server stopped");
    });
    isServerRunning = false;
    return { success: true, message: "TCP Server stopped" };
};

app.route("/tcpserver/start", startTCP);
app.route("/tcpserver/stop", stopTCP);
app.route("/tcpserver/restart", restartTCP);

// start the server after on system start up
setTimeout(() => {
    startTCPServer();
}, 5000);

export default app;
