// @ts-check

const addUsersTableToDb = require("../../backend/addUsersTableToDb");
const addDbEntry = require("../../backend/db/addDbEntry");
const updateUsersTableSchema = require("../../backend/updateUsersTableSchema");
const varDatabaseDbHandler = require("../../backend/varDatabaseDbHandler");
const hashPassword = require("../../dsql/hashPassword");

/** @type {import("../../../types").APICreateUserFunction} */
module.exports = async function apiCreateUser({
    encryptionKey,
    payload,
    database,
    userId,
    useLocal,
}) {
    const dbFullName = database;

    const finalEncryptionKey =
        encryptionKey || process.env.DSQL_ENCRYPTION_PASSWORD;

    if (!finalEncryptionKey) {
        return {
            success: false,
            msg: "No encryption key provided",
            payload: null,
        };
    }

    if (!finalEncryptionKey?.match(/.{8,}/)) {
        return {
            success: false,
            msg: "Encryption key must be at least 8 characters long",
            payload: null,
        };
    }

    const hashedPassword = hashPassword({
        encryptionKey: finalEncryptionKey,
        password: String(payload.password),
    });

    payload.password = hashedPassword;

    const fieldsQuery = `SHOW COLUMNS FROM users`;

    let fields = await varDatabaseDbHandler({
        queryString: fieldsQuery,
        database: dbFullName,
        useLocal,
    });

    if (!fields?.[0]) {
        const newTable = await addUsersTableToDb({
            userId: Number(userId),
            database: dbFullName,
            useLocal,
            payload: payload,
        });

        fields = await varDatabaseDbHandler({
            queryString: fieldsQuery,
            database: dbFullName,
            useLocal,
        });
    }

    if (!fields?.[0]) {
        return {
            success: false,
            msg: "Could not create users table",
        };
    }

    const fieldsTitles = fields.map(
        (/** @type {any} */ fieldObject) => fieldObject.Field
    );

    let invalidField = null;

    for (let i = 0; i < Object.keys(payload).length; i++) {
        const key = Object.keys(payload)[i];
        if (!fieldsTitles.includes(key)) {
            await updateUsersTableSchema({
                userId: Number(userId),
                database: dbFullName,
                newPayload: {
                    [key]: payload[key],
                },
            });
        }
    }

    if (invalidField) {
        return {
            success: false,
            msg: `${invalidField} is not a valid field!`,
        };
    }

    const existingUserQuery = `SELECT * FROM users WHERE email = ?${
        payload.username ? " OR username = ?" : ""
    }`;
    const existingUserValues = payload.username
        ? [payload.email, payload.username]
        : [payload.email];

    const existingUser = await varDatabaseDbHandler({
        queryString: existingUserQuery,
        queryValuesArray: existingUserValues,
        database: dbFullName,
        useLocal,
    });

    if (existingUser?.[0]) {
        return {
            success: false,
            msg: "User Already Exists",
            payload: null,
        };
    }

    const addUser = await addDbEntry({
        dbContext: "Dsql User",
        paradigm: "Full Access",
        dbFullName: dbFullName,
        tableName: "users",
        data: {
            ...payload,
            image: "/images/user-preset.png",
            image_thumbnail: "/images/user-preset-thumbnail.png",
        },
    });

    if (addUser?.insertId) {
        const newlyAddedUserQuery = `SELECT id,first_name,last_name,email,username,phone,image,image_thumbnail,city,state,country,zip_code,address,verification_status,more_user_data FROM users WHERE id='${addUser.insertId}'`;

        const newlyAddedUser = await varDatabaseDbHandler({
            queryString: newlyAddedUserQuery,
            database: dbFullName,
            useLocal,
        });

        return {
            success: true,
            payload: newlyAddedUser[0],
        };
    } else {
        return {
            success: false,
            msg: "Could not create user",
            sqlResult: addUser,
            payload: null,
        };
    }
};
