import sql from "mssql";
import { checkHostnamePort } from "../utils/checkHostNamePort.js";
import { sqlConfig } from "./prodSqlConfig.js";
import { createLogger } from "../logger/logger.js";
import { returnFunc } from "../utils/return.js";
import { validateEnv } from "../utils/envValidator.js";

const env = validateEnv(process.env);

export let pool: any;
export let connected: boolean = false;
let reconnecting = false;

export const initializeProdPool = async () => {
    const log = createLogger({ module: "prodSql" });

    const serverUp = await checkHostnamePort(`${env.PROD_SERVER}:1433`);

    if (!serverUp) {
        reconnectToSql();
        return returnFunc({
            success: false,
            module: "prodSql",
            level: "fatal",
            message: `The sql ${env.PROD_SERVER} is not reachable`,
            data: [],
        });
    }

    // if you were restarting from the endpoint you get this lovely error
    if (connected) {
        return returnFunc({
            success: false,
            module: "prodSql",
            level: "error",
            message: `There is already a connection to ${env.PROD_PLANT_TOKEN}`,
            data: [],
        });
    }
    try {
        pool = await sql.connect(sqlConfig);

        log.info(
            `Connected to ${sqlConfig?.server}, using DB: ${sqlConfig?.database}`
        );
        connected = true;
    } catch (error) {
        log.fatal(
            `${JSON.stringify(
                error
            )}, "There was an error connecting to the pool."`
        );
        reconnectToSql();
        // throw new Error("There was an error closing the sql connection");
    }
};

const reconnectToSql = async () => {
    const log = createLogger({ module: "prodSql" });
    if (reconnecting) return;
    reconnecting = true;

    let delay = 2000; // start at 2s
    let attempts = 0;
    const maxAttempts = 10; // or limit by time, e.g. 2 min total

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

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

        const serverUp = await checkHostnamePort(`${env.PROD_SERVER}:1433`);

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

        try {
            pool = sql.connect(sqlConfig);

            log.info(
                `Connected to ${sqlConfig?.server}, and looking at ${sqlConfig?.database}`
            );
            reconnecting = false;
            connected = true;
        } catch (error) {
            log.fatal(
                `${JSON.stringify(
                    error
                )}, "There was an error connecting to the pool."`
            );
            delay = Math.min(delay * 2, 30000); // exponential backoff up to 30s
            // throw new Error("There was an error closing the sql connection");
        }
    }

    if (!connected) {
        log.fatal(
            { notify: true },
            "Max reconnect attempts reached on the prodSql server. Stopping retries."
        );
        reconnecting = false;
        // optional: exit process or alert someone here
        // process.exit(1);
    }
};

export const closePool = async () => {
    const log = createLogger({ module: "prodSql" });
    if (!connected) {
        log.error("There is no connection a connection.");
        return { success: false, message: "There is already a connection." };
    }
    try {
        await pool.close();
        log.info("Connection pool closed");
        connected = false;
        return {
            success: true,
            message: "The sql server connection has been closed",
        };
    } catch (error) {
        log.fatal(
            { notify: true },
            `${JSON.stringify(
                error
            )},  "There was an error closing the sql connection"`
        );
    }
};
