vehicle/running/costs/wlc.js

/**
 * Brings various whole life cost components
 * @module
 */

import { requiredKeys } from '../../../keys/required';
// import { calculate as calculateFuelAndElectric } from './components/fuelandelectric/ppm';
import { buildConfig } from './components/config';
import { getCost as fuelAndElectricCosts } from '../result';

/**
 *
 * @returns {struct}
*/
const checkRequiredKeys = (skv_config) => {
    // ensure we have the basic keys required
    const required_keys = [
        'total_miles',
        'vehicle',
        'include_components',
    ];

    const rst_required_keys = requiredKeys(skv_config, required_keys);
    // check to see if any keys missing
    if (
        !rst_required_keys.success
        || rst_required_keys.data.length > 0
    ) {
        let missing_keys_msg = '';

        if (rst_required_keys.data.length > 0) {
            missing_keys_msg = ` // Missing required keys: ${rst_required_keys.data}`;
        }

        throw new Error(` ${rst_required_keys.msg}${missing_keys_msg} for running.vehicle.journey`);
    }
};

/**
 * check should calculate is specifies a list of components to calculate
 * @param {any} value
 */
const checkIncludeComponents = (data) => {
    // valid values for include_components
    const valid_values = [
        'fuel and electric',
        'depreciation',
        'mot',
        'ved',
        'servicing',
        // contract hire (bch, flb, pch, pcp?)
        // non reclaimable vat
        // class 1a nic vehicle benefit
        // amount paid
        // residual value
    ];

    // check passed in value is an array
    if (!Array.isArray(data)) {
        throw new Error('include_components is not an array');
    }

    // check passed in value is not empty
    if (data.length === 0) {
        throw new Error('No calculations requested');
    }

    // check only valid strings are passed in
    data.forEach((value) => {
        if (!valid_values.includes(value)) {
            throw new Error('Invalid value in include_components');
        }
    });
};

/**
 * change a component name in to a valid key format to return
 * => convert component name to lowercase and spaces for underscores
 * @param {string} str_component_name
 * @returns {string}
 */
const changeStringToKey = (str_component_name) => str_component_name.toLowerCase().replace(/ /g, '_');

/**
 * bring together individual components to form a wlc calculation
 * @param {struct} skv_config
 * @returns {struct}
 */
const combineComponents = (skv_config) => {
    const skv_return = {};
    let skv_component_cfg = {};
    let skv_component_data = {};

    // loop over skv_config.include_components
    skv_config.include_components.forEach((component_name) => {
        if (component_name === 'fuel and electric') {
            // do any manipulation of the config here before passing to the component
            skv_component_cfg = buildConfig(skv_config, 'fuel and electric');
            skv_component_data = fuelAndElectricCosts(skv_component_cfg);
        }

        const component_key = changeStringToKey(component_name);
        skv_return[component_key] = skv_component_data;
    });

    return skv_return;
};

/**
 * overall wlc calculation
 * @param {struct} skv_config
 * @returns {struct}
 */
const calculate = (skv_config) => {
    let skv_return = {
        total: {},
    };

    // check to see if we have the required keys
    checkRequiredKeys(skv_config);

    // check should calculate is an array and not empty
    checkIncludeComponents(skv_config.include_components);

    // merge the results from all the components calculating and existing
    // skv_return object with total key
    skv_return = { ...combineComponents(skv_config), ...skv_return };

    // TODO: finish totals when more components

    return skv_return;
};

export {
    calculate,
    checkRequiredKeys,
    checkIncludeComponents,
    combineComponents,
    changeStringToKey,
};