import {
	isBoolean,
	isNumber,
	isString,
	readSetting as readSettingImpl,
	writeSetting as writeSettingImpl,
} from "qrc:/js/lib/utils";
import {
	LegacyAutomaticProcessConfig,
	isLegacyAutomaticProcessConfig,
	AutomaticProcessConfig,
	isAutomaticProcessConfig,
} from "qrc:/js/lib/graph_post_processing";
import {
	isSheetMaterialUniqueMembers,
} from "qrc:/js/lib/generated/typeguard";
import {
	BendLineEngravingMode,
	isBendLineEngravingMode,
} from "qrc:/js/lib/bend_line_engraving_mode";

/**
 * Settings local to the machine (stored in QSettings)
 *
 * Interface is not intended to be instantiated.
 * Interface can be considered a map that defines available entry keys and the respective types.
 *
 * Note:  Using snake_case as settings keys are potentially case-insensitive.
 */
interface Settings {
	sheetMergingEnabled: boolean;
	automaticProcessConfig: AutomaticProcessConfig;
	legacyAutomaticProcessConfig: LegacyAutomaticProcessConfig;
	defaultSheetMaterialId: string | undefined;
	defaultBendLineEngravingMode: BendLineEngravingMode;
	bendLineEngravingLength: number;
	lstConfigJson: string;
}

const typeGuardMap: {[index in keyof Settings]: (arg: unknown) => arg is Settings[index]} = {
	sheetMergingEnabled: isBoolean,
	automaticProcessConfig: isAutomaticProcessConfig,
	legacyAutomaticProcessConfig: isLegacyAutomaticProcessConfig,
	defaultSheetMaterialId: isString,
	defaultBendLineEngravingMode: isBendLineEngravingMode,
	bendLineEngravingLength: isNumber,
	lstConfigJson: isString,
};

const initialValueMap: {[index in keyof Settings]: () => Settings[index]} = {
	// Note:  accessing previously used setting so there is no inconsistent program behaviour
	sheetMergingEnabled: () => readSettingImpl("sheetNodeMergingEnabled", true, isBoolean),
	automaticProcessConfig: () => ({}),
	legacyAutomaticProcessConfig: () => ({
		automaticDeburringEnabled: false,
		manualDeburringEnabled: false,
	}),
	// Note:  accessing previously used setting so there is no inconsistent program behaviour
	defaultSheetMaterialId: () => readSettingImpl("globalMaterial", undefined, isSheetMaterialUniqueMembers)?.identifier,
	defaultBendLineEngravingMode: () => "none",
	bendLineEngravingLength: () => 0,
	lstConfigJson: () => "",
};

const prefix = "gui_local_settings_";

const settingsKeyMap = Object.freeze<{[index in keyof Settings]: string}>({
	sheetMergingEnabled: "sheet_merging_enabled",
	automaticProcessConfig: "automatic_process_config_v0",
	legacyAutomaticProcessConfig: "automatic_process_config",
	defaultSheetMaterialId: "default_sheet_material_id",
	defaultBendLineEngravingMode: "default_bend_line_engraving_mode",
	bendLineEngravingLength: "bend_line_engraving_length",
	lstConfigJson: "lst_config_json",
});

export function readSetting<Key extends keyof Settings>(key: Key): Settings[Key] {
	return readSettingImpl(
		prefix + settingsKeyMap[key],
		initialValueMap[key](),
		typeGuardMap[key],
	);
}

export function writeSetting<Key extends keyof Settings>(key: Key, value: Settings[Key]): void {
	return writeSettingImpl(prefix + settingsKeyMap[key], value);
}
