/**
 * Cost calculation implementation
 *
 * All function must be implemented graph-agnostic.
 * This allows for:
 * 	- computation of price-previews without the need to modify the graph
 * 	- safe utilization in internal script engine
 * 	- ...
 *
 * Functions must *not* use
 * 	- wsi4.graph
 * 	- wsi4.node
 * 	- ...
 */

import {
	assert,
	isNonNegativeNumber,
} from "qrc:/js/lib/utils";

export class Costs {
	material = 0;
	setup = 0;
	unit = 0;

	constructor(materialCosts: number, setupCosts: number, unitCosts: number) {
		assert(isNonNegativeNumber(materialCosts), "Invalid material costs");
		assert(isNonNegativeNumber(setupCosts), "Invalid setup costs");
		assert(isNonNegativeNumber(unitCosts), "Invalid unit costs");

		/**
		 * Material costs *including* multiplicity
		 */
		this.material = materialCosts;

		/**
		 * Setup costs
		 */
		this.setup = setupCosts;

		/**
		 * Unit costs *including* multiplicity
		 */
		this.unit = unitCosts;
	}
}

export function addCosts(costs: readonly Readonly<Costs|undefined>[]): Costs|undefined {
	return costs.some(c => c === undefined) ? undefined : costs.reduce((acc: Costs, c) => {
		assert(c !== undefined);
		return {
			material: acc.material + c.material,
			setup: acc.setup + c.setup,
			unit: acc.unit + c.unit,
		};
	}, new Costs(0, 0, 0));
}
