import sql from "mssql";
import { prodSqlConfig } from "./utils/prodServerConfig.js";
import { createLog } from "../logger/logger.js";
import { db } from "../../../database/dbclient.js";
import { settings } from "../../../database/schema/settings.js";
import { eq } from "drizzle-orm";
import { installed } from "../../index.js";
import { checkHostnamePort } from "../../globalUtils/pingServer.js";
import { serverSettings } from "../server/controller/settings/getSettings.js";

let pool: any;
let connected: boolean = false;
export const initializeProdPool = async () => {
    if (!installed) {
        createLog(
            "info",
            "lst",
            "sqlProd",
            "The server was not installed will reconnect in 5 seconds"
        );
        setTimeout(() => {
            initializeProdPool();
        }, 5 * 1000);

        return { success: false, message: "The server is not installed." };
    }
    // const dbServer = await db
    //     .select()
    //     .from(settings)
    //     .where(eq(settings.name, "dbServer"));

    // the move to the go version for settings
    const dbServer = serverSettings.filter(
        (n: any) => n.name === "dbServer"
    ) as any;

    const serverUp = await checkHostnamePort(`${dbServer[0].value}:1433`);

    if (!serverUp) {
        createLog(
            "error",
            "lst",
            "server",
            `The sql ${dbServer[0].value} is not reachable`
        );
        return {
            success: false,
            message: `The sql ${dbServer[0].value} is not reachable`,
            data: [],
        };
    }

    // make sure the server is not set to localhost this will prevent some weird issues later but can be localhost on the dev
    // const serverLoc = await db
    //     .select()
    //     .from(settings)
    //     .where(eq(settings.name, "dbServer"));

    const serverLoc = serverSettings.filter(
        (n: any) => n.name === "dbServer"
    ) as any;
    if (
        serverLoc[0].value === "localhost" &&
        process.env.NODE_ENV !== "development"
    ) {
        createLog(
            "error",
            "lst",
            "sqlProd",
            "The server is set to localhost, and you are not in development mode."
        );
        return {
            success: false,
            message:
                "The server is set to localhost, and you are not in development mode.",
            data: [],
        };
    }

    // if you were restarting from the endpoint you get this lovely error
    if (connected) {
        createLog("error", "lst", "sqlProd", "There is already a connection.");
        return { success: false, message: "There is already a connection." };
    }
    try {
        const config = await prodSqlConfig();
        pool = await sql.connect(config!);

        createLog(
            "info",
            "lst",
            "sqlProd",
            `Connected to ${config?.server}, and looking at ${config?.database}`
        );
        connected = true;
        return {
            success: true,
            message: "The sql server connection has been closed",
        };
    } catch (error) {
        createLog(
            "error",
            "lst",
            "sqlProd",
            `${JSON.stringify(
                error
            )}, "There was an error connecting to the pool."`
        );
        throw new Error("There was an error closing the sql connection");
    }
};

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

export async function query(queryToRun: string, name: string) {
    /**
     * Just an extra catch incase someone tried to run a query while we were not connected to the server or sql server
     */
    // const dbServer = await db
    //     .select()
    //     .from(settings)
    //     .where(eq(settings.name, "dbServer"));

    const dbServer = serverSettings.filter(
        (n: any) => n.name === "dbServer"
    ) as any;
    const serverUp = await checkHostnamePort(`${dbServer[0].value}:1433`);

    if (!serverUp) {
        createLog(
            "error",
            "lst",
            "server",
            `The sql ${dbServer[0].value} is not reachable`
        );
        return {
            success: false,
            message: `The sql ${dbServer[0].value} is not reachable`,
            data: [],
        };
    }

    if (!connected) {
        createLog(
            "error",
            "lst",
            "server",
            `The sql ${dbServer[0].value} is not connected`
        );
        return {
            success: false,
            message: `The sql ${dbServer[0].value} is not not connected`,
            data: [],
        };
    }
    /**
     * We no longer need to send over the plant token change as we do it inside the query function.
     */
    // const plantToken = await db
    //     .select()
    //     .from(settings)
    //     .where(eq(settings.name, "plantToken"));
    const plantToken = serverSettings.filter(
        (n: any) => n.name === "plantToken"
    ) as any;
    const query = queryToRun.replaceAll("test1", plantToken[0].value);

    try {
        const result = await pool.request().query(query);

        return {
            success: true,
            message: `Query results for: ${name}`,
            data: result.recordset,
        };
    } catch (error: any) {
        if (error.code === "ETIMEOUT") {
            createLog(
                "error",
                "lst",
                "sqlProd",
                `${JSON.stringify(
                    error
                )}, ${name} did not run due to a timeout.`
            );
            //throw new Error(`${name} query did not run due to a timeout.`);
            return {
                success: false,
                message: `${name} query did not run due to a timeout.`,
                data: [],
            };
        }

        if (error.code === "EREQUEST") {
            // throw new Error(
            //     `${name} encoutnered an error ${error.originalError.info.message}`
            // );
            return {
                success: false,
                message: `${name} encoutnered an error ${error.originalError.info.message}`,
                data: [],
            };
        }

        //console.log(error.originalError.info.message);
        //EREQUEST
        //throw new Error(`${name} encoutnered an error ${error.code}`);
    }
}
