// @ts-check

const http = require("http");
const encrypt = require("../../package-shared/functions/dsql/encrypt");
const grabHostNames = require("../../package-shared/utils/grab-host-names");
const apiGoogleLogin = require("../../package-shared/functions/api/users/social/api-google-login");
const getAuthCookieNames = require("../../package-shared/functions/backend/cookies/get-auth-cookie-names");
const {
    writeAuthFile,
} = require("../../package-shared/functions/backend/auth/write-auth-files");

/**
 * SERVER FUNCTION: Login with google Function
 * ==============================================================================
 *
 * @async
 *
 * @param {object} params - main params object
 * @param {string} [params.key] - API full access key
 * @param {string} params.token - Google access token gotten from the client side
 * @param {string} [params.database] - Target database name
 * @param {http.ServerResponse} [params.response] - HTTPS response object
 * @param {string} [params.encryptionKey] - Encryption key
 * @param {string} [params.encryptionSalt] - Encryption salt
 * @param {string[]} [params.additionalFields] - Additional Fields to be added to the user object
 * @param {Object<string,string|number>} [params.additionalData] - Additional Data to by added on creation of User
 * @param {string | number} [params.apiUserID] - API user ID
 * @param {boolean} [params.useLocal] - Whether to use a remote database instead of API
 *
 * @returns { Promise<import("../../package-shared/types").APILoginFunctionReturn> }
 */
async function googleAuth({
    key,
    token,
    database,
    response,
    encryptionKey,
    encryptionSalt,
    additionalFields,
    additionalData,
    apiUserID,
    useLocal,
}) {
    const grabedHostNames = grabHostNames();
    const { host, port, scheme } = grabedHostNames;

    const finalEncryptionKey =
        encryptionKey || process.env.DSQL_ENCRYPTION_PASSWORD;
    const finalEncryptionSalt =
        encryptionSalt || process.env.DSQL_ENCRYPTION_SALT;

    if (!finalEncryptionKey?.match(/.{8,}/)) {
        console.log("Encryption key is invalid");
        return {
            success: false,
            payload: null,
            msg: "Encryption key is invalid",
        };
    }
    if (!finalEncryptionSalt?.match(/.{8,}/)) {
        console.log("Encryption salt is invalid");
        return {
            success: false,
            payload: null,
            msg: "Encryption salt is invalid",
        };
    }

    /**
     * Check inputs
     *
     * @description Check inputs
     */

    if (!token || token?.match(/ /)) {
        return {
            success: false,
            payload: null,
            msg: "Please enter Google Access Token",
        };
    }

    /**
     * Initialize HTTP response variable
     */

    /** @type {import("../../package-shared/types").APILoginFunctionReturn} */
    let httpResponse = {
        success: false,
    };

    /**
     * Check for local DB settings
     *
     * @description Look for local db settings in `.env` file and by pass the http request if available
     */
    const { DSQL_DB_HOST, DSQL_DB_USERNAME, DSQL_DB_PASSWORD, DSQL_DB_NAME } =
        process.env;

    if (
        DSQL_DB_HOST?.match(/./) &&
        DSQL_DB_USERNAME?.match(/./) &&
        DSQL_DB_PASSWORD?.match(/./) &&
        DSQL_DB_NAME?.match(/./) &&
        useLocal
    ) {
        httpResponse = await apiGoogleLogin({
            token,
            additionalFields,
            database: DSQL_DB_NAME,
            additionalData,
        });
    } else {
        /**
         * Make https request
         *
         * @description make a request to datasquirel.com
         * @type {{ success: boolean, user: import("../../package-shared/types").DATASQUIREL_LoggedInUser | null, msg?: string, dsqlUserId?: number } | null } - Https response object
         */
        httpResponse = await new Promise((resolve, reject) => {
            const reqPayload = JSON.stringify({
                token,
                database,
                additionalFields,
                additionalData,
            });

            const httpsRequest = scheme.request(
                {
                    method: "POST",
                    headers: {
                        "Content-Type": "application/json",
                        "Content-Length": Buffer.from(reqPayload).length,
                        Authorization:
                            key ||
                            process.env.DSQL_FULL_ACCESS_API_KEY ||
                            process.env.DSQL_API_KEY,
                    },
                    port,
                    hostname: host,
                    path: `/api/user/${
                        apiUserID || grabedHostNames.user_id
                    }/google-login`,
                },

                /**
                 * Callback Function
                 *
                 * @description https request callback
                 */
                (response) => {
                    var str = "";

                    response.on("data", function (chunk) {
                        str += chunk;
                    });

                    response.on("end", function () {
                        resolve(JSON.parse(str));
                    });

                    response.on("error", (err) => {
                        reject(err);
                    });
                }
            );
            httpsRequest.write(reqPayload);
            httpsRequest.end();
        });
    }

    /**
     * Make https request
     *
     * @description make a request to datasquirel.com
     */
    if (httpResponse?.success && httpResponse?.payload) {
        let encryptedPayload = encrypt({
            data: JSON.stringify(httpResponse.payload),
            encryptionKey: finalEncryptionKey,
            encryptionSalt: finalEncryptionSalt,
        });

        const cookieNames = getAuthCookieNames({
            database,
            userId: apiUserID || process.env.DSQL_API_USER_ID,
        });

        if (httpResponse.csrf) {
            writeAuthFile(
                httpResponse.csrf,
                JSON.stringify(httpResponse.payload)
            );
        }

        httpResponse["cookieNames"] = cookieNames;
        httpResponse["key"] = String(encryptedPayload);

        const authKeyName = cookieNames.keyCookieName;
        const csrfName = cookieNames.csrfCookieName;

        response?.setHeader("Set-Cookie", [
            `${authKeyName}=${encryptedPayload};samesite=strict;path=/;HttpOnly=true;Secure=true`,
            `${csrfName}=${httpResponse.payload?.csrf_k};samesite=strict;path=/;HttpOnly=true`,
        ]);
    }

    return httpResponse;
}

module.exports = googleAuth;