import {
	getTable,
} from "./table_utils";
import {
	assert,
	getRowForThreshold,
} from "./utils";

export interface ConsumableConsumption {
	// ID of the consumable
	consumableId: string;

	// [units]
	consumedUnits: number;
}

export function consumableConsumptionsForProcess(processId: string, overallUnitTimeInSeconds: number): ConsumableConsumption[] {
	const overallUnitTimeInHours = overallUnitTimeInSeconds / 3600;
	return getTable("processConsumableRate")
		.filter(row => row.processId === processId)
		.map(row => ({
			consumableId: row.consumableId,
			consumedUnits: overallUnitTimeInHours * row.unitsPerHour,
		}));
}

type SpecificRate = SheetCuttingProcessConsumableRate | TubeCuttingProcessConsumableRate;
function specificConsumableConsumptionImpl<T extends SpecificRate>(
	allRates: readonly Readonly<T>[],
	args: {
		thickness: number,
		overallUnitTimeInSeconds: number,
	},
): ConsumableConsumption[] {
	const overallUnitTimeInHours = args.overallUnitTimeInSeconds / 3600;
	const consumableIds = Array.from(new Set(allRates.map(row => row.consumableId)));
	const result: ConsumableConsumption[] = [];
	consumableIds.forEach(consumableId => {
		const filteredSortedRates = Array.from(allRates)
			.filter(row => row.consumableId === consumableId)
			.sort((lhs, rhs) => lhs.thickness - rhs.thickness);
		const rate = getRowForThreshold(filteredSortedRates, row => row.thickness >= args.thickness);
		if (rate === undefined) {
			return;
		}
		result.push({
			consumableId: consumableId,
			consumedUnits: overallUnitTimeInHours * rate.unitsPerHour,
		});
	});
	return result;
}

export function sheetCuttingConsumableConsumptionsForProcess(args: {
	sheetCuttingProcessId: string,
	thickness: number,
	overallUnitTimeInSeconds: number,
}): ConsumableConsumption[] {
	const allMatchingRates: readonly Readonly<SheetCuttingProcessConsumableRate>[] = getTable("sheetCuttingProcessConsumableRate").filter(row => row.sheetCuttingProcessId === args.sheetCuttingProcessId);
	return specificConsumableConsumptionImpl(allMatchingRates, args);
}

export function tubeCuttingConsumableConsumptionsForProcess(args: {
	tubeCuttingProcessId: string,
	thickness: number,
	overallUnitTimeInSeconds: number,
}): ConsumableConsumption[] {
	const allMatchingRates: readonly Readonly<TubeCuttingProcessConsumableRate>[] = getTable("tubeCuttingProcessConsumableRate").filter(row => row.tubeCuttingProcessId === args.tubeCuttingProcessId);
	return specificConsumableConsumptionImpl(allMatchingRates, args);
}

export interface ConsumableCosts {
	consumable: Consumable;
	// [currency]
	costs: number;
}

export function computeConsumableCosts(consumptions: ConsumableConsumption[], consumablesInput?: readonly Readonly<Consumable>[]): ConsumableCosts[] {
	const consumables = consumablesInput ?? getTable("consumable");
	return consumptions.map(consumption => {
		const consumable = consumables.find(row => row.identifier === consumption.consumableId);
		assert(consumable !== undefined, "Tables inconsistent");
		return {
			consumable: consumable,
			costs: consumption.consumedUnits * consumable.costsPerUnit,
		};
	});
}
