/**
 * Typesafe wrapper for wsi4.sharedData
 */

import {
	BendLineEngravingMode,
	isBendLineEngravingMode,
} from "./bend_line_engraving_mode";
import {
	AutomaticProcessConfig,
	isAutomaticProcessConfig,
} from "./graph_post_processing";
import {
	isBoolean,
	isNumber,
	isString,
} from "./utils";

/**
 * Interface is not intended to be instantiated.
 * Interface can be considered a map that defines available entry keys and the respective types.
 *
 * The actual shared data is managed via a StringIndexedInterface.
 */
interface SharedData {
	// [ms]; 0 disables timeout
	nestorTimeLimit: number;
	sheetMergingEnabled: boolean;
	automaticProcessConfig: AutomaticProcessConfig;
	prismNestingTimeLimit: number; // [milliseconds] 0 is considered no time limit
	defaultSheetMaterialId: string | undefined;
	defaultBendLineEngravingMode: BendLineEngravingMode;
}

type SharedDataKey = keyof SharedData;

const typeGuardMap: {[index in SharedDataKey]: (arg: unknown) => arg is SharedData[index]} = {
	nestorTimeLimit: isNumber,
	sheetMergingEnabled: isBoolean,
	automaticProcessConfig: (arg: unknown): arg is AutomaticProcessConfig => isAutomaticProcessConfig(arg),
	prismNestingTimeLimit: isNumber,
	defaultSheetMaterialId: (arg: unknown): arg is string | undefined => arg === undefined || isString(arg),
	defaultBendLineEngravingMode: (arg: unknown): arg is BendLineEngravingMode => isBendLineEngravingMode(arg),
};

const defaultValueMap: {[index in SharedDataKey]: SharedData[index]} = {
	nestorTimeLimit: 100,
	sheetMergingEnabled: true,
	automaticProcessConfig: {
		automaticDeburringEnabled: false,
		manualDeburringEnabled: false,
	},
	prismNestingTimeLimit: 100,
	defaultSheetMaterialId: undefined,
	defaultBendLineEngravingMode: "none",
};

/**
 * Read value from shared data
 *
 * Returns default value in case it is not set.
 */
export function getSharedDataEntry<Key extends SharedDataKey>(key: Key, sharedData = wsi4.sharedData.read()): SharedData[Key] {
	const value = sharedData[key];
	if (!typeGuardMap[key](value)) {
		return defaultValueMap[key];
	} else {
		return value;
	}
}

/**
 * Create updated shared data
 *
 * Submitted value overwrites an existing value (if any).
 */
export function createUpdatedSharedData<Key extends SharedDataKey>(key: Key, value: SharedData[Key], sharedData = wsi4.sharedData.read()): StringIndexedInterface {
	if (value !== undefined) {
		sharedData[key] = value;
	} else if (sharedData[key] !== undefined) {
		delete sharedData[key];
	}
	return sharedData;
}
