import sanitizeHtml from "sanitize-html";
import sanitizeHtmlOptions from "../html/sanitizeHtmlOptions";
import DB_HANDLER from "../../../utils/backend/global-db/DB_HANDLER";
import DSQL_USER_DB_HANDLER from "../../../utils/backend/global-db/DSQL_USER_DB_HANDLER";
import encrypt from "../../dsql/encrypt";
import LOCAL_DB_HANDLER from "../../../utils/backend/global-db/LOCAL_DB_HANDLER";

type Param = {
    dbContext?: "Master" | "Dsql User";
    paradigm?: "Read Only" | "Full Access";
    dbFullName?: string;
    tableName: string;
    encryptionKey?: string;
    encryptionSalt?: string;
    data: any;
    tableSchema?: import("../../../types").DSQL_TableSchemaType;
    identifierColumnName: string;
    identifierValue: string | number;
    useLocal?: boolean;
};

/**
 * # Update DB Function
 * @description
 */
export default async function updateDbEntry({
    dbContext,
    paradigm,
    dbFullName,
    tableName,
    data,
    tableSchema,
    identifierColumnName,
    identifierValue,
    encryptionKey,
    encryptionSalt,
    useLocal,
}: Param): Promise<object | null> {
    /**
     * Check if data is valid
     */
    if (!data || !Object.keys(data).length) return null;

    const isMaster = useLocal
        ? true
        : dbContext?.match(/dsql.user/i)
        ? false
        : dbFullName && !dbFullName.match(/^datasquirel$/)
        ? false
        : true;

    /** @type {(a1:any, a2?:any)=> any } */
    const dbHandler: (a1: any, a2?: any) => any = useLocal
        ? LOCAL_DB_HANDLER
        : isMaster
        ? DB_HANDLER
        : DSQL_USER_DB_HANDLER;

    ////////////////////////////////////////
    ////////////////////////////////////////
    ////////////////////////////////////////

    /**
     * Declare variables
     *
     * @description Declare "results" variable
     */
    const dataKeys = Object.keys(data);

    let updateKeyValueArray = [];
    let updateValues = [];

    for (let i = 0; i < dataKeys.length; i++) {
        try {
            const dataKey = dataKeys[i];
            // @ts-ignore
            let value = data[dataKey];

            const targetFieldSchemaArray = tableSchema
                ? tableSchema?.fields?.filter(
                      (field) => field.fieldName === dataKey
                  )
                : null;
            const targetFieldSchema =
                targetFieldSchemaArray && targetFieldSchemaArray[0]
                    ? targetFieldSchemaArray[0]
                    : null;

            if (value == null || value == undefined) continue;

            const htmlRegex = /<[^>]+>/g;

            if (targetFieldSchema?.richText || String(value).match(htmlRegex)) {
                value = sanitizeHtml(value, sanitizeHtmlOptions);
            }

            if (targetFieldSchema?.encrypted) {
                value = encrypt({
                    data: value,
                    encryptionKey,
                    encryptionSalt,
                });
            }

            if (typeof value === "object") {
                value = JSON.stringify(value);
            }

            if (targetFieldSchema?.pattern) {
                const pattern = new RegExp(
                    targetFieldSchema.pattern,
                    targetFieldSchema.patternFlags || ""
                );
                if (!pattern.test(value)) {
                    console.log("DSQL: Pattern not matched =>", value);
                    value = "";
                }
            }

            if (typeof value === "string" && value.match(/^null$/i)) {
                value = {
                    toSqlString: function () {
                        return "NULL";
                    },
                };
            }

            if (typeof value === "string" && !value.match(/./i)) {
                value = {
                    toSqlString: function () {
                        return "NULL";
                    },
                };
            }

            updateKeyValueArray.push(`\`${dataKey}\`=?`);

            if (typeof value == "number") {
                updateValues.push(String(value));
            } else {
                updateValues.push(value);
            }

            ////////////////////////////////////////
            ////////////////////////////////////////
        } catch (/** @type {any} */ error: any) {
            ////////////////////////////////////////
            ////////////////////////////////////////

            console.log(
                "DSQL: Error in parsing data keys in update function =>",
                error.message
            );
            continue;
        }
    }

    ////////////////////////////////////////
    ////////////////////////////////////////

    updateKeyValueArray.push(`date_updated='${Date()}'`);
    updateKeyValueArray.push(`date_updated_code='${Date.now()}'`);

    ////////////////////////////////////////
    ////////////////////////////////////////

    const query = `UPDATE \`${dbFullName}\`.\`${tableName}\` SET ${updateKeyValueArray.join(
        ","
    )} WHERE \`${identifierColumnName}\`=?`;

    updateValues.push(identifierValue);

    const updatedEntry = isMaster
        ? await dbHandler(query, updateValues)
        : await dbHandler({
              paradigm,
              queryString: query,
              queryValues: updateValues,
          });

    /**
     * Return statement
     */
    return updatedEntry;
}