/**
 * Copyright 2013-2026 the original author or authors from the JHipster project.
 *
 * This file is part of the JHipster project, see https://www.jhipster.tech/
 * for more information.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import sortKeys from 'sort-keys';
const appendTitle = (title, config, value) => {
    if (Array.isArray(value))
        value = value[0];
    if (value === undefined)
        return title;
    const newTitle = typeof value === 'string' && value !== 'no' ? value : `${config}(${value})`;
    return `${title}${title.length === 0 ? '' : '-'}${newTitle}`;
};
/**
 * Create a matrix from options
 * @example
 * const matrix = fromMatrix({ a: [true, false], b: [true, false] });
 * // {
 * //  'a(true)-b(true)': { a: true, b: true },
 * //  'a(true)-b(false)': { a: true, b: false },
 * //  'a(false)-b(true)': { a: false, b: true },
 * //  'a(false)-b(false)': { a: false, b: false },
 * // }
 */
export const fromMatrix = (configMatrix) => {
    const configEntries = Object.entries(configMatrix);
    const samples = configEntries.reduce((previousValue, currentValue) => {
        const [config, configValues] = currentValue;
        return previousValue.flatMap(([previousName, previousConfig]) => configValues.map((value) => {
            return [
                // @ts-expect-error fix type
                appendTitle(previousName, config, value),
                {
                    ...previousConfig,
                    [config]: value,
                },
            ];
        }));
    }, [['', {}]]);
    return Object.fromEntries(samples);
};
const applyExtendedMatrix = (matrixEntries, configMatrix) => {
    const configEntries = Object.entries(configMatrix);
    const additionalMatrixTemp = configEntries.reduce((currentArray, [configName, configValues]) => {
        const currentConfigObjects = configValues.map(configValue => ({
            [configName]: configValue,
        }));
        return currentArray.flatMap(existingConfig => currentConfigObjects.map(currentObject => ({ ...existingConfig, ...currentObject })));
    }, [{}]);
    const additionalMatrix = [];
    while (additionalMatrixTemp.length > 0) {
        additionalMatrix.push(additionalMatrixTemp.shift());
        if (additionalMatrixTemp.length > 0) {
            additionalMatrix.push(additionalMatrixTemp.pop());
        }
    }
    matrixEntries.forEach((entry, matrixIndex) => {
        let matrixName = entry[0];
        const matrixConfig = entry[1];
        let newValues = additionalMatrix[matrixIndex % additionalMatrix.length];
        Object.entries(newValues).forEach(([configName, configValue]) => {
            if (typeof configValue === 'object' && !Array.isArray(configValue) && 'value' in configValue) {
                const additionalValues = configValue.additional;
                configValue = configValue.value;
                newValues = { ...newValues, ...additionalValues, [configName]: configValue };
            }
            matrixName = appendTitle(matrixName, configName, configValue);
        });
        entry.splice(0, entry.length);
        entry.push(matrixName, Object.assign(matrixConfig, newValues));
    });
    return matrixEntries;
};
/**
 * Apply new matrix value to existing matrix
 * @example
 * const matrix = extendMatrix(fromMatrix({ initialMatrix: [true, false] }), { toBeMerged: [true, false] });
 * // {
 * //  'initialMatrix(true)-toBeMerged(true)': { initialMatrix: true, toBeMerged: true },
 * //  'initialMatrix(false)-toBeMerged(false)': { initialMatrix: false, toBeMerged: false },
 * // }
 */
export const extendMatrix = (matrix, configMatrix) => Object.fromEntries(applyExtendedMatrix(Object.entries(matrix), configMatrix));
export const extendFilteredMatrix = (matrix, filter, extendedConfig) => {
    const matrixEntries = Object.entries(matrix);
    const filteredEntries = matrixEntries.filter(([_name, sample]) => filter(sample));
    applyExtendedMatrix(filteredEntries, extendedConfig);
    return Object.fromEntries(matrixEntries);
};
export const buildSamplesFromMatrix = (samples, { commonConfig = {} } = {}) => sortKeys(commonConfig ?
    Object.fromEntries(Object.entries(samples).map(([name, sample]) => [
        name,
        {
            ...sample,
            ...commonConfig,
        },
    ]))
    : samples, { deep: true });
