process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";

import { serve } from "@hono/node-server";
import { serveStatic } from "@hono/node-server/serve-static";
import { OpenAPIHono } from "@hono/zod-openapi";
import { cors } from "hono/cors";
import { html } from "hono/html";
import { logger } from "hono/logger";
import os from "os";
import auth from "./services/auth/authService.js";
import dataMart from "./services/dataMart/dataMartService.js";
import eom from "./services/eom/eomService.js";
// custom routes
import scalar from "./services/general/route/scalar.js";
import { createLog } from "./services/logger/logger.js";
import loggerService from "./services/logger/loggerService.js";
import logistics from "./services/logistics/logisticsService.js";
import { sendEmail } from "./services/notifications/controller/sendMail.js";
import notify from "./services/notifications/notifyService.js";
import ocme from "./services/ocme/ocmeService.js";
import ocpService from "./services/ocp/ocpService.js";
import printers from "./services/printers/printerService.js";
import produser from "./services/prodUser/prodUser.js";
import qualityRequest from "./services/quality/qualityService.js";
import rfid from "./services/rfid/rfidService.js";
import {
	getSettings,
	serverSettings,
} from "./services/server/controller/settings/getSettings.js";
import system from "./services/server/systemServer.js";
import sqlService from "./services/sqlServer/sqlService.js";
import tcpServer from "./services/tcpServer/tcpServer.js";

// create the main prodlogin here
const username = "lst_user";
const password = "Alpla$$Prod";
export const lstAuth = btoa(`${username}:${password}`);

// checking to make sure we have the settings intialized
// const { data: settingsData, error: settingError } = await tryCatch(
//     db.select().from(settings)
// );

// if (settingError) {
//     throw Error("Error getting settings from the db. critical error.");
// }

const serverIntialized: any = await getSettings();

export const installed =
	serverIntialized.length === 0 && process.env.NODE_ENV !== "development"
		? false
		: true;
createLog("info", "LST", "server", `Server is installed: ${installed}`);

const app = new OpenAPIHono({ strict: false });

// middle ware
if (process.env.NODE_ENV === "development") {
	app.use("*", logger());
}

app.use(
	"*",
	cors({
		origin: [
			"http://localhost:3000",
			"http://localhost:5173",
			"http://localhost:4000",
			"http://localhost:4200",
		], // Allow all origins
		allowHeaders: ["Content-Type", "Authorization", "X-Requested-With"],
		allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"],
		//exposeHeaders: ["Content-Length", "X-Kuma-Revision"],
		credentials: true, // Allow credentials if needed
		maxAge: 600,
	}),
);

// Middleware to normalize route case
// app.use("*", async (c, next) => {
//   //   const lowercasedUrl = c.req.url.toLowerCase();
//   console.log("Incoming Request:", c.req.url, c.req.method);
//   //   // If the URL is already lowercase, continue as usual
//   //   if (c.req.url === lowercasedUrl) {
//   await next();
//   //   }

//   //   // Otherwise, re-route internally
//   //   return c.redirect(lowercasedUrl, 308); // 308 preserves the HTTP method
// });

app.doc("/api/ref", {
	openapi: "3.0.0",
	info: {
		version: "2.0.0",
		title: "LST API",
	},
});

const routes = [
	scalar,
	auth,
	// apiHits,
	system,
	tcpServer,
	sqlService,
	logistics,
	rfid,
	printers,
	loggerService,
	ocpService,
	notify,
	eom,
	dataMart,
	qualityRequest,
	produser,
] as const;

const appRoutes = routes.forEach((route) => {
	app.route("/api/", route);
});

app.route("/ocme/", ocme);

//--------------- lst v1 proxy ----------------------\\
// app.all("/api/v1/*", (c) => {
//     const path = c.req.path.replace("/api/v1/", ""); // Extract the subpath
//     const query = c.req.query() ? "?" + new URLSearchParams(c.req.query()).toString() : ""; // Get query params
//     return proxy(`http://localhost:4900/${path}${query}`, {
//         headers: {
//             ...c.req.header(),
//             "X-Forwarded-For": "127.0.0.1",
//             "X-Forwarded-Host": c.req.header("host"),
//         },
//     });
// });

// app.all("/system/*", (c) => {
//     const path = c.req.path.replace("/system/", ""); // Extract the subpath
//     const query = c.req.query() ? "?" + new URLSearchParams(c.req.query()).toString() : ""; // Get query params
//     return proxy(`http://localhost:4200/${path}${query}`, {
//         headers: {
//             ...c.req.header(),
//             "X-Forwarded-For": "127.0.0.1",
//             "X-Forwarded-Host": c.req.header("host"),
//         },
//     });
// });

//---------------------------------------------------\\

// the catch all api route
app.all("/api/*", (c) => c.json({ error: "API route not found" }, 404));

const newPageDoc = `
<!doctype html>
      <h1>Hello!</h1>
`;

app.all("*", (c) => {
	const testServers = ["test1", "test2", "test3"];
	const server = serverIntialized.filter((n: any) => n.name === "plantToken");

	let url = "";

	if (c.req.url.includes("localhost")) {
		url = `http://localhost:5500/lst/app/old${c.req.path}`;
	} else if (testServers.includes(server[0].value)) {
		const dbServer = serverIntialized.filter((n: any) => n.name === "dbServer");
		url = `https://${dbServer[0].value}.alpla.net/lst/app/old${c.req.path}`;
	} else {
		url = `https://${server[0].value}prod.alpla.net/lst/app/old${c.req.path}`;
	}
	const target = url;
	const waitSeconds = 10;
	return c.html(html`<!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8"/>
        <title>Lst Moved</title>
        <style>
          body{font-family:sans-serif;display:flex;flex-direction:column;
          align-items:center;justify-content:center;height:100vh;}
          button{margin-top:1rem;padding:0.6rem 1.2rem;font-size:1rem;cursor:pointer;}
        </style>
      </head>
      <body>
        <h1>We’ve moved!</h1>
		<p>With new security and updating to mobile version the app had to be moved. You will be redirected to.</p>
        <p><a href="${target}">${target}</a></p>
        <p>Redirecting in <span id="countdown">${waitSeconds}</span> seconds…</p>
        <button id="goNow">Go now</button>
        <script>
          let s = ${waitSeconds};
          const el = document.getElementById('countdown');
          const btn = document.getElementById('goNow');
          const timer = setInterval(()=>{
            s--;
            el.textContent = s;
            if(s <= 0){ clearInterval(timer); window.location.href='${target}'; }
          },1000);
          btn.addEventListener('click',()=>{
            clearInterval(timer); window.location.href='${target}';
          });
        </script>
      </body>
    </html>`);
});

// app.all("/*", (c) => {
// 	console.log(c.req.path);
// 	return c.html(html`${newPageDoc}`);
// });

// front end static files
//app.use("/*", serveStatic({ root: "./frontend/dist" }));
//app.use("*", serveStatic({ path: "./frontend/dist/index.html" }));

// Handle app exit signals
process.on("SIGINT", async () => {
	console.log("\nGracefully shutting down...");
	//await closePool();
	process.exit(0);
});

process.on("SIGTERM", async () => {
	console.log("Received termination signal, closing database...");
	//await closePool();
	process.exit(0);
});

process.on("uncaughtException", async (err) => {
	console.log("Uncaught Exception:", err);
	//await closePool();
	const emailData = {
		email: "blake.matthes@alpla.com", // should be moved to the db so it can be reused.
		subject: `${os.hostname()} has just encountered a crash.`,
		template: "serverCrash",
		context: {
			error: err,
			plant: `${os.hostname()}`,
		},
	};

	await sendEmail(emailData);
	//process.exit(1);
});

process.on("beforeExit", async () => {
	console.log("Process is about to exit...");
	//await closePool();
	process.exit(0);
});

const port =
	process.env.NODE_ENV === "development"
		? process.env.VITE_SERVER_PORT
		: process.env.PROD_PORT;

const ocmeport = process.env.OCME_PORT;
serve(
	{
		fetch: app.fetch,
		port: Number(port),
		hostname: "0.0.0.0",
	},
	(info) => {
		createLog(
			"info",
			"LST",
			"server",
			`Server is running on http://${info.address}:${info.port}`,
		);
	},
);

/**
 * Only for ocme until we get them switched over to the single port setup.
 */
// const setting = await db.select().from(settings);
const setting = serverSettings;
const isActive = setting.filter((n) => n.name === "ocmeService");
if (ocmeport && isActive[0]?.value === "1") {
	serve(
		{
			fetch: app.fetch,
			port: Number(ocmeport),
			hostname: "0.0.0.0",
		},
		(info) => {
			createLog(
				"info",
				"LST",
				"server",
				`Ocme section is listening on http://${info.address}:${info.port}`,
			);
		},
	);
}

export type AppRoutes = typeof appRoutes;
