import { computeHashFloat } from "../../primitives/numbers/computeHashFloat.js";
import { computeStringHash } from "../../primitives/strings/computeStringHash.js";

/**
 * Recursively computes object hash
 * @param {Object} value
 * @param {number} [depth=3] Maximum recursion depth
 * @returns {number}
 */
export function computeObjectHash(value, depth = 3) {
    if (value === undefined) {
        return 1;
    }

    if (value === null) {
        return 2;
    }

    let hash = 0;

    const pType = typeof value;

    if (pType === "string") {
        hash = computeStringHash(value);
    } else if (pType === "number") {
        hash = computeHashFloat(value);
    } else if (pType === "boolean") {
        hash = value ? 1 : 0;
    } else if (pType === "object") {

        if (depth <= 0) {
            hash = 3;
        } else {

            // TODO implement special path for arrays and typed arrays

            for (let p in value) {

                const pNameHash = computeStringHash(p);

                const pValue = value[p];

                const pHash = pNameHash ^ computeObjectHash(pValue, depth - 1);

                hash = ((hash << 5) - hash) + pHash;

                hash |= 0; // Convert to 32bit integer
            }

        }

    }


    return hash;
}
