import {
	isStringIndexedInterface,
} from "qrc:/js/lib/generated/typeguard";
import {
	assert,
	ElisionMode,
	getKeysOfObject,
	isBoolean,
	isElisionMode,
	isNumber,
	readSetting,
	writeSetting,
} from "qrc:/js/lib/utils";

export interface ExportSettings {
	threeDimStepGenerated: boolean;
	threeDimStepInput: boolean;
	threeDimHtml: boolean;
	twoDimDxfCutting: boolean;
	twoDimDxfBending: boolean;
	twoDimSvg: boolean;
	twoDimGeoCutting: boolean;
	twoDimGeoBending: boolean;
	bendDrawing: boolean;
	bendDrawingDocx: boolean;
	coatingDetails: boolean;
	threeDimPng: boolean;
	joiningInstructions: boolean;
	jobCards: boolean;
	jobCardsDocx: boolean;
	calculation: boolean;
	quotation: boolean;
	subGraphs: boolean;
	erpInputData: boolean;
	bomCsv: boolean;
	createArticleDir: boolean;
	nameElisionMode: ElisionMode;
	nameElisionThreshold: number;
}

const defaultExportSettings: ExportSettings = {
	threeDimStepGenerated: true,
	threeDimStepInput: true,
	threeDimHtml: true,
	twoDimDxfCutting: true,
	twoDimDxfBending: true,
	twoDimSvg: true,
	twoDimGeoCutting: true,
	twoDimGeoBending: true,
	bendDrawing: true,
	bendDrawingDocx: false,
	coatingDetails: true,
	threeDimPng: true,
	joiningInstructions: true,
	jobCards: true,
	jobCardsDocx: false,
	calculation: true,
	quotation: false,
	subGraphs: false,
	erpInputData: true,
	bomCsv: true,
	createArticleDir: true,
	nameElisionMode: "none",
	nameElisionThreshold: 10,
};

const typeGuardMap: {[key in keyof ExportSettings]: (arg: unknown) => arg is ExportSettings[key]} = {
	threeDimStepGenerated: isBoolean,
	threeDimStepInput: isBoolean,
	threeDimHtml: isBoolean,
	twoDimDxfCutting: isBoolean,
	twoDimDxfBending: isBoolean,
	twoDimSvg: isBoolean,
	twoDimGeoCutting: isBoolean,
	twoDimGeoBending: isBoolean,
	bendDrawing: isBoolean,
	bendDrawingDocx: isBoolean,
	coatingDetails: isBoolean,
	threeDimPng: isBoolean,
	joiningInstructions: isBoolean,
	jobCards: isBoolean,
	jobCardsDocx: isBoolean,
	calculation: isBoolean,
	quotation: isBoolean,
	subGraphs: isBoolean,
	erpInputData: isBoolean,
	bomCsv: isBoolean,
	createArticleDir: isBoolean,
	nameElisionMode: isElisionMode,
	nameElisionThreshold: isNumber,
};

function isType<Key extends keyof ExportSettings>(key: Key, arg: unknown): arg is ExportSettings[Key] {
	return typeGuardMap[key](arg);
}

export function isExportSettings(arg: unknown): arg is ExportSettings {
	return isStringIndexedInterface(arg) && getKeysOfObject(defaultExportSettings)
		.every(key => isType(key, arg[key]));
}

function isPartialExportSettings(arg: unknown): arg is Partial<ExportSettings> {
	return isStringIndexedInterface(arg) && getKeysOfObject(defaultExportSettings)
		.every(key => !(key in arg) || isType(key, arg[key]));
}

const settingsKey = "export_settings";

function updateWithDefaultValue<Key extends keyof ExportSettings>(key: Key, value: Partial<ExportSettings>): Partial<ExportSettings> {
	value[key] = defaultExportSettings[key];
	return value;
}

export function getDefaultExportSetting<Key extends keyof ExportSettings>(key: Key): ExportSettings[Key] {
	return defaultExportSettings[key];
}

export function readExportSettings(): ExportSettings {
	const incompleteSettings = readSetting(settingsKey, defaultExportSettings, isPartialExportSettings);
	const completeSettings = getKeysOfObject(defaultExportSettings)
		.filter(key => !isType(key, incompleteSettings[key]))
		.reduce((acc: Partial<ExportSettings>, key) => updateWithDefaultValue(key, acc), incompleteSettings);
	assert(isExportSettings(completeSettings), "Expecting complete Export settings");
	return completeSettings;
}

export function writeExportSettings(value: ExportSettings): void {
	writeSetting(settingsKey, value);
}
