import sql from "mssql";
import { gpSqlConfig } from "../configs/gpSql.config.js";
import { createLogger } from "../logger/logger.controller.js";
import { checkHostnamePort } from "../utils/checkHost.utils.js";
import { returnFunc } from "../utils/returnHelper.utils.js";

export let pool2: sql.ConnectionPool;
export let connected: boolean = false;
export let reconnecting = false;
// start the delay out as 2 seconds
let delayStart = 2000;
let attempt = 0;
const maxAttempts = 10;

export const connectGPSql = async () => {
	const serverUp = await checkHostnamePort(
		`${process.env.GP_SERVER ?? "usmcd1vms011"}:1433`,
	);
	if (!serverUp) {
		// we will try to reconnect
		connected = false;
		reconnectToSql;
		return returnFunc({
			success: false,
			level: "error",
			module: "system",
			subModule: "db",
			message: "GP server is offline or unreachable.",
		});
	}

	// if we are trying to click restart from the api for some reason we want to kick back and say no
	if (connected) {
		return returnFunc({
			success: false,
			level: "error",
			module: "system",
			subModule: "db",
			message: "The Sql server is already connected.",
		});
	}

	// try to connect to the sql server
	try {
		pool2 = new sql.ConnectionPool(gpSqlConfig);
		await pool2.connect();
		connected = true;
		return returnFunc({
			success: true,
			level: "info",
			module: "system",
			subModule: "db",
			message: `${gpSqlConfig.server} is connected to ${gpSqlConfig.database}`,
			data: [],
			notify: false,
		});
	} catch (error) {
		console.log(error);
		reconnectToSql;
		return returnFunc({
			success: false,
			level: "error",
			module: "system",
			subModule: "db",
			message: "Failed to connect to the gp sql server.",
			data: [error],
			notify: false,
		});
	}
};

export const closePool = async () => {
	if (!connected) {
		return returnFunc({
			success: false,
			level: "error",
			module: "system",
			subModule: "db",
			message: "There is no connection to the prod server currently.",
		});
	}

	try {
		await pool2.close();
		connected = false;
		return returnFunc({
			success: true,
			level: "info",
			module: "system",
			subModule: "db",
			message: "The sql connection has been closed.",
		});
	} catch (error) {
		connected = false;

		return returnFunc({
			success: false,
			level: "error",
			module: "system",
			subModule: "db",
			message: "There was an error closing the sql connection",
			data: [error],
		});
	}
};
export const reconnectToSql = async () => {
	const log = createLogger({
		module: "system",
		subModule: "db",
	});
	if (reconnecting) return;

	//set reconnecting to true while we try to reconnect
	reconnecting = true;

	while (!connected && attempt < maxAttempts) {
		attempt++;
		log.info(
			`Reconnect attempt ${attempt}/${maxAttempts} in ${delayStart / 1000}s ...`,
		);

		await new Promise((res) => setTimeout(res, delayStart));

		const serverUp = await checkHostnamePort(
			`${process.env.GP_SERVER ?? "usmcd1vms011"}:1433`,
		);

		if (!serverUp) {
			delayStart = Math.min(delayStart * 2, 30000); // exponential backoff until up to 30000
			continue;
		}

		try {
			pool2 = await sql.connect(gpSqlConfig);
			reconnecting = false;
			connected = true;
			log.info(`${gpSqlConfig.server} is connected to ${gpSqlConfig.database}`);
		} catch (error) {
			delayStart = Math.min(delayStart * 2, 30000);
			log.error({ error }, "Failed to reconnect to the prod sql server.");
		}
	}

	if (!connected && attempt >= maxAttempts) {
		log.error(
			{ notify: true },
			"Max reconnect attempts reached on the prodSql server. Stopping retries.",
		);

		reconnecting = false;
		// TODO: exit alert someone here
	}
};
