// @ts-check

import { APICreateUserFunctionParams } from "../../../types";
import addUsersTableToDb from "../../backend/addUsersTableToDb";
import addDbEntry from "../../backend/db/addDbEntry";
import updateUsersTableSchema from "../../backend/updateUsersTableSchema";
import varDatabaseDbHandler from "../../backend/varDatabaseDbHandler";
import hashPassword from "../../dsql/hashPassword";

/**
 * # API Create User
 */
export default async function apiCreateUser({
    encryptionKey,
    payload,
    database,
    userId,
    useLocal,
}: APICreateUserFunctionParams) {
    const dbFullName = database;
    const API_USER_ID = userId || process.env.DSQL_API_USER_ID;

    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 ${dbFullName}.users`;

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

    if (!fields?.[0]) {
        const newTable = await addUsersTableToDb({
            userId: Number(API_USER_ID),
            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((fieldObject: any) => 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(API_USER_ID),
                database: dbFullName,
                newPayload: {
                    [key]: payload[key],
                },
            });
        }
    }

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

    const existingUserQuery = `SELECT * FROM ${dbFullName}.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:
                process.env.DSQL_DEFAULT_USER_IMAGE ||
                "/images/user-preset.png",
            image_thumbnail:
                process.env.DSQL_DEFAULT_USER_IMAGE ||
                "/images/user-preset-thumbnail.png",
        },
        useLocal,
    });

    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 ${dbFullName}.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,
        };
    }
}