/**
 * Curve validation strategies for machine curves and generic curves.
 * Extracted from validationUtils.js for modularity.
 */

function isSorted(arr) {
    return arr.every((_, i) => i === 0 || arr[i] >= arr[i - 1]);
}

function isUnique(arr) {
    return new Set(arr).size === arr.length;
}

function areNumbers(arr) {
    return arr.every((x) => typeof x === "number");
}

function validateDimensionStructure(dimension, name, logger) {
    const validatedDimension = {};

    for (const [key, value] of Object.entries(dimension)) {
        if (typeof value !== "object") {
            logger.warn(`Dimension '${name}' key '${key}' is not valid. Returning to default.`);
            return false;
        }
        else if (!Array.isArray(value.x) || !Array.isArray(value.y)) {
            logger.warn(`Dimension '${name}' key '${key}' is missing x or y arrays. Converting to arrays.`);
            value.x = Object.values(value.x);
            value.y = Object.values(value.y);
            if (!Array.isArray(value.x) || !Array.isArray(value.y)) {
                logger.warn(`Dimension '${name}' key '${key}' is not valid. Returning to default.`);
                return false;
            }
        }
        else if (value.x.length !== value.y.length) {
            logger.warn(`Dimension '${name}' key '${key}' has mismatched x and y lengths. Ignoring this key.`);
            return false;
        }
        else if (!isSorted(value.x)) {
            logger.warn(`Dimension '${name}' key '${key}' has unsorted x values. Sorting...`);
            const indices = value.x.map((_v, i) => i);
            indices.sort((a, b) => value.x[a] - value.x[b]);
            value.x = indices.map(i => value.x[i]);
            value.y = indices.map(i => value.y[i]);
        }
        if (!isUnique(value.x)) {
            logger.warn(`Dimension '${name}' key '${key}' has duplicate x values. Removing duplicates...`);
            const seen = new Set();
            const uniqueX = [];
            const uniqueY = [];
            for (let i = 0; i < value.x.length; i++) {
                if (!seen.has(value.x[i])) {
                    seen.add(value.x[i]);
                    uniqueX.push(value.x[i]);
                    uniqueY.push(value.y[i]);
                }
            }
            value.x = uniqueX;
            value.y = uniqueY;
        }
        if (!areNumbers(value.y)) {
            logger.warn(`Dimension '${name}' key '${key}' has non-numeric y values. Ignoring this key.`);
            return false;
        }

        validatedDimension[key] = value;
    }
    return validatedDimension;
}

function validateCurve(configValue, defaultCurve, logger) {
    if (!configValue || typeof configValue !== "object" || Object.keys(configValue).length === 0) {
        logger.warn("Curve is missing or invalid. Defaulting to basic curve.");
        return defaultCurve;
    }
    const validatedCurve = validateDimensionStructure(configValue, "curve", logger);
    if (!validatedCurve) {
        return defaultCurve;
    }
    return validatedCurve;
}

function validateMachineCurve(configValue, defaultCurve, logger) {
    if (!configValue || typeof configValue !== "object" || Object.keys(configValue).length === 0) {
        logger.warn("Curve is missing or invalid. Defaulting to basic curve.");
        return defaultCurve;
    }
    const { nq, np } = configValue;
    if (!nq || typeof nq !== "object" || !np || typeof np !== "object") {
        logger.warn("Curve must contain valid 'nq' and 'np' objects. Defaulting to basic curve.");
        return defaultCurve;
    }
    const validatedNq = validateDimensionStructure(nq, "nq", logger);
    const validatedNp = validateDimensionStructure(np, "np", logger);
    if (!validatedNq || !validatedNp) {
        return defaultCurve;
    }
    return { nq: validatedNq, np: validatedNp };
}

module.exports = {
    validateCurve,
    validateMachineCurve,
    validateDimensionStructure,
    isSorted,
    isUnique,
    areNumbers
};
