import {
	readCalcSettings,
} from "qrc:/js/lib/calc_settings";
import {
	DocumentOrientation,
	FileType,
	ProcessType,
} from "qrc:/js/lib/generated/enum";
import {
	getArticleName,
	isComponentArticle,
	projectName,
	serializeUndirectedConnectedComponent,
} from "qrc:/js/lib/graph_utils";
import {
	askQuestion,
	getDirectoryPath,
	showError,
	showInfo,
} from "qrc:/js/lib/gui_utils";
import {
	createGltfFutures,
	createPngFutures,
	VertexAnd,
} from "qrc:/js/lib/node_utils";
import {
	isSubProcess,
} from "qrc:/js/lib/process";
import {
	getGraphUserDataEntry,
} from "qrc:/js/lib/userdata_config";
import {
	assert,
	cleanRelativeDirPath,
	elide,
	isBoolean,
	isEqual,
	isString,
	readSetting as legacyReadSetting,
	renderDefaultPng,
	writeSetting,
} from "qrc:/js/lib/utils";
import {
	isCompatibleToNodeUserDataEntry,
	nodeUserDatumOrDefault,
} from "qrc:/js/lib/userdata_utils";
import {
	getSettingOrDefault,
} from "qrc:/js/lib/settings_table";
import {
	isExportReady,
} from "qrc:/js/lib/manufacturing_state_util";
import {
	defaultSceneForVertex,
	sceneForVertex,
} from "qrc:/js/lib/scene_utils";

import {
	getFutureResult,
} from "qrc:/js/lib/future";
import {
	createBendDrawing,
} from "./export_bend_drawing";
import {
	createBendDrawingsData,
	createBendDrawingsDocx,
} from "./export_bend_drawing_docx";
import {
	createCsv as createBomCsv,
	createEntry as createBomEntry,
} from "./export_bom";
import {
	createInternalCalc,
} from "./export_calculation";
import {
	createCoatingDetails,
} from "./export_coating_details";
import {
	createPath,
	symlink,
	writeFile,
} from "./export_fs_util";
import {
	createGraphRepresentation,
	ScaleDataConfig,
} from "./export_graph_representation";
import {
	createJobCard,
} from "./export_job_card";
import {
	createJobCardData,
	createJobCardDocx,
} from "./export_job_card_docx";
import {
	exportThreeDimHtml,
} from "./export_three_dim_html";
import {
	exportJoiningView,
} from "./export_joining_view";
import {
	createQuotationDocx,
	createQuotationInput,
} from "./gui_export_quotation";
import {
	ExportSettings,
	readExportSettings,
} from "./gui_export_settings";
import {
	readSetting,
} from "./gui_local_settings";
import {
	guiConstraintLevelMap,
	guiReplyStateLevelMap,
} from "./gui_manufacturing_state";

// Must be used for boolean properties only.
function exportOptionSet<Key extends keyof ExportSettings>(key: Key): boolean {
	const value = readExportSettings()[key];
	assert(isBoolean(value));
	return value;
}

function computeElidedName(arg: string): string {
	const exportSettings = readExportSettings();
	const mode = exportSettings["nameElisionMode"];
	const threshold = exportSettings["nameElisionThreshold"];
	return elide(arg, mode, threshold);
}

function computeElidedArticleName(vertex: Vertex): string {
	return computeElidedName(getArticleName(vertex));
}

function exportGraph(cleanExportDirPath: string, gltfFutures: VertexAnd<ArrayBufferFuture>[]) {
	const exportNodeData = (cleanExportBaseDirPath: string, cleanDirPath: string, vertex: Vertex) => {
		const processType = wsi4.node.processType(vertex);
		const articleProcessDir = createPath(cleanDirPath, wsi4.util.translate(processType));
		const imagesSubDir = createPath(cleanExportBaseDirPath, wsi4.util.translate("ExportImages"));
		const globalProcessBaseDir = createPath(cleanExportBaseDirPath, wsi4.util.translate("ExportWorkSteps"));
		const globalProcessDir = createPath(globalProcessBaseDir, wsi4.util.translate(processType));

		const nodeAttachments = isCompatibleToNodeUserDataEntry("attachments", vertex) ? nodeUserDatumOrDefault("attachments", vertex) : [];
		for (const attachment of nodeAttachments) {
			const path = writeFile(globalProcessDir, attachment.name, "", wsi4.util.fromBase64(wsi4.util.stringToArrayBuffer(attachment.data)));
			if (path === undefined) {
				wsi4.util.error(wsi4.util.translate("ErrorWritingFile"));
				continue;
			}
			if (exportOptionSet("createArticleDir")) {
				const linkPath = symlink(path, articleProcessDir);
				if (linkPath === undefined) {
					wsi4.util.error(wsi4.util.translate("ErrorCreatingLink"));
				}
			}
		}

		const articleName = computeElidedArticleName(vertex);
		(() => {
			if (!exportOptionSet("threeDimStepGenerated")) {
				return;
			}
			const assembly = wsi4.node.assembly(vertex);
			if (assembly === undefined) {
				return;
			}
			const content = wsi4.geo.assembly.createStep(assembly);
			if (content === undefined) {
				return wsi4.throwError("exportGraph(): Cannot create file content");
			}
			const path = writeFile(globalProcessDir, articleName, "step", content);
			if (path === undefined) {
				wsi4.util.error("exportGraph(): " + wsi4.util.translate("ErrorWritingFile"));
				return;
			}
			if (exportOptionSet("createArticleDir")) {
				const linkPath = symlink(path, articleProcessDir);
				if (linkPath === undefined) {
					wsi4.util.error("exportGraph(): " + wsi4.util.translate("ErrorCreatingLink"));
					return;
				}
			}
			return;
		})();

		(() => {
			if (!exportOptionSet("threeDimStepInput")) {
				return;
			}
			const assembly = wsi4.node.inputAssembly(vertex);
			if (assembly === undefined) {
				return;
			}
			const content = wsi4.geo.assembly.createStep(assembly);
			if (content === undefined) {
				return wsi4.throwError("exportGraph(): Cannot create file content");
			}
			const path = writeFile(globalProcessDir, articleName + "_input", "step", content);
			if (path === undefined) {
				wsi4.util.error("exportGraph(): " + wsi4.util.translate("ErrorWritingFile"));
				return;
			}
			if (exportOptionSet("createArticleDir")) {
				const linkPath = symlink(path, articleProcessDir);
				if (linkPath === undefined) {
					wsi4.util.error("exportGraph(): " + wsi4.util.translate("ErrorCreatingLink"));
					return;
				}
			}
			return;
		})();

		{
			const twoDimRep = wsi4.node.twoDimRep(vertex);
			const layered = wsi4.node.layered(vertex);
			const workStepType = wsi4.node.workStepType(vertex);
			if (twoDimRep !== undefined && workStepType === "sheetCutting") {
				(() => {
					if (!exportOptionSet("twoDimDxfCutting")) {
						return;
					}
					const scene = defaultSceneForVertex(vertex);
					const content = wsi4.geo.util.renderScene(scene, FileType.dxf, {});
					if (content === undefined) {
						return wsi4.throwError("Cannot create file content");
					}
					const dxfPath = writeFile(globalProcessDir, articleName, "dxf", content);
					if (dxfPath === undefined) {
						wsi4.util.error("exportGraph(): " + wsi4.util.translate("ErrorWritingFile") + ": " + (dxfPath === undefined ? "undef" : dxfPath));
						return;
					}
					if (exportOptionSet("createArticleDir")) {
						const linkPath = symlink(dxfPath, articleProcessDir);
						if (linkPath === undefined) {
							wsi4.util.error("exportGraph(): " + wsi4.util.translate("ErrorCreatingLink"));
							return;
						}
					}
					return;
				})();
				(() => {
					if (!exportOptionSet("twoDimSvg")) {
						return;
					}
					const scene = sceneForVertex(
						vertex,
						{
							bendLineShowLabels: true,
							bendLineShowAffectedSegments: false,
						},
					);
					const content = wsi4.geo.util.renderScene(scene, FileType.svg, {});
					if (content === undefined) {
						return wsi4.throwError("Cannot create file content");
					}
					const svgPath = writeFile(imagesSubDir, wsi4.util.toKey(vertex), "svg", content);
					if (svgPath === undefined) {
						wsi4.util.error("exportGraph(): " + wsi4.util.translate("ErrorWritingFile"));
						return;
					}
					return;
				})();
				(() => {
					if (!exportOptionSet("twoDimGeoCutting")) {
						return;
					}
					const scene = defaultSceneForVertex(vertex);
					const content = wsi4.geo.util.renderScene(scene, FileType.geo, {});
					if (content === undefined) {
						return wsi4.throwError("Cannot create file content");
					}
					const geoPath = writeFile(globalProcessDir, articleName, "geo", content);
					if (geoPath === undefined) {
						wsi4.util.error("exportGraph(): " + wsi4.util.translate("ErrorWritingFile") + ": " + (geoPath === undefined ? "undef" : geoPath));
						return;
					}
					if (exportOptionSet("createArticleDir")) {
						const linkPath = symlink(geoPath, articleProcessDir);
						if (linkPath === undefined) {
							wsi4.util.error("exportGraph(): " + wsi4.util.translate("ErrorCreatingLink"));
							return;
						}
					}
					return;
				})();
			} else if (twoDimRep !== undefined && workStepType === "sheetBending") {
				(() => {
					if (!exportOptionSet("twoDimDxfBending")) {
						return;
					}
					const scene = defaultSceneForVertex(vertex);
					const content = wsi4.geo.util.renderScene(scene, FileType.dxf, {});
					if (content === undefined) {
						return wsi4.throwError("Cannot create file content");
					}
					const dxfPath = writeFile(globalProcessDir, articleName, "dxf", content);
					if (dxfPath === undefined) {
						wsi4.util.error("exportGraph(): " + wsi4.util.translate("ErrorWritingFile") + ": " + (dxfPath === undefined ? "undef" : dxfPath));
						return;
					}
					if (exportOptionSet("createArticleDir")) {
						const linkPath = symlink(dxfPath, articleProcessDir);
						if (linkPath === undefined) {
							wsi4.util.error("exportGraph(): " + wsi4.util.translate("ErrorWritingFile"));
							return;
						}
					}
					return;
				})();
				(() => {
					if (!exportOptionSet("twoDimSvg")) {
						return;
					}
					const scene = sceneForVertex(
						vertex,
						{
							bendLineShowLabels: true,
							bendLineShowAffectedSegments: true,
						},
					);
					const content = wsi4.geo.util.renderScene(scene, FileType.svg, {});
					if (content === undefined) {
						return;
					}
					const svgPath = writeFile(imagesSubDir, wsi4.util.toKey(vertex), "svg", content);
					if (svgPath === undefined) {
						wsi4.util.error("exportGraph(): " + wsi4.util.translate("ErrorWritingFile"));
					}
				})();
				(() => {
					if (!exportOptionSet("twoDimGeoBending")) {
						return;
					}
					const scene = defaultSceneForVertex(vertex);
					const content = wsi4.geo.util.renderScene(scene, FileType.geo, {});
					if (content === undefined) {
						return wsi4.throwError("Cannot create file content");
					}
					const geoPath = writeFile(globalProcessDir, articleName, "geo", content);
					if (geoPath === undefined) {
						wsi4.util.error("exportGraph(): " + wsi4.util.translate("ErrorWritingFile") + ": " + (geoPath === undefined ? "undef" : geoPath));
						return;
					}
					if (exportOptionSet("createArticleDir")) {
						const linkPath = symlink(geoPath, articleProcessDir);
						if (linkPath === undefined) {
							wsi4.util.error("exportGraph(): " + wsi4.util.translate("ErrorWritingFile"));
							return;
						}
					}
					return;
				})();
				(() => {
					if (!exportOptionSet("bendDrawing")) {
						return;
					}
					const documentRows = createBendDrawing(vertex);
					const pdfBa = wsi4.documentCreator.renderIntoPdf(documentRows, {orientation: DocumentOrientation.landscape});
					const path = writeFile(globalProcessDir, articleName + "_bend_drawing", "pdf", pdfBa);
					if (path === undefined) {
						wsi4.util.error("exportArticleData(): " + wsi4.util.translate("ErrorWritingFile"));
						return;
					}
					if (exportOptionSet("createArticleDir")) {
						const linkPath = symlink(path, articleProcessDir);
						if (linkPath === undefined) {
							wsi4.util.error("exportGraph(): " + wsi4.util.translate("ErrorWritingFile"));
							return;
						}
					}
				})();

				(() => {
					if (!exportOptionSet("bendDrawingDocx")) {
						return;
					}
					const bendDrawingData = createBendDrawingsData(vertex);
					if (bendDrawingData === undefined) {
						return;
					}
					const templatePath = readSetting("bendDrawingTemplatePath");
					const tmpl = wsi4.io.fs.readFile(templatePath === "" ? ":/templates/benddrawing.docx" : templatePath);
					if (tmpl === undefined) {
						wsi4.util.error("Error reading benddrawing template.");
						return;
					}
					const docxBa = createBendDrawingsDocx(tmpl, bendDrawingData);
					if (docxBa === undefined) {
						return;
					}
					const path = writeFile(globalProcessDir, articleName + "_bend_drawing", "docx", docxBa);
					if (path === undefined) {
						wsi4.util.error("exportArticleData(): " + wsi4.util.translate("ErrorWritingFile"));
						return;
					}
					if (exportOptionSet("createArticleDir")) {
						const linkPath = symlink(path, articleProcessDir);
						if (linkPath === undefined) {
							wsi4.util.error(wsi4.util.translate("ErrorWritingFile"));
							return;
						}
					}
				})();
			} else if (layered !== undefined && workStepType === "tubeCutting") {
				(() => {
					if (!exportOptionSet("twoDimDxfCutting")) {
						return;
					}
					const scene = sceneForVertex(vertex, {
						tubeCuttingShowTubeContours: true,
						tubeCuttingShowVirtualCuts: false,
					});
					const content = wsi4.geo.util.renderScene(scene, FileType.dxf, {});
					if (content === undefined) {
						return wsi4.throwError("Cannot create file content");
					}
					const dxfPath = writeFile(globalProcessDir, articleName, "dxf", content);
					if (dxfPath === undefined) {
						wsi4.util.error("exportGraph(): " + wsi4.util.translate("ErrorWritingFile") + ": " + (dxfPath === undefined ? "undef" : dxfPath));
						return;
					}
					if (exportOptionSet("createArticleDir")) {
						const linkPath = symlink(dxfPath, articleProcessDir);
						if (linkPath === undefined) {
							wsi4.util.error("exportGraph(): " + wsi4.util.translate("ErrorCreatingLink"));
							return;
						}
					}
					return;
				})();
				(() => {
					if (!exportOptionSet("twoDimSvg")) {
						return;
					}
					const scene = sceneForVertex(vertex, {tubeCuttingShowTubeContours: true});
					const content = wsi4.geo.util.renderScene(scene, FileType.svg, {});
					if (content === undefined) {
						return wsi4.throwError("Cannot create file content");
					}
					const svgPath = writeFile(imagesSubDir, wsi4.util.toKey(vertex), "svg", content);
					if (svgPath === undefined) {
						wsi4.util.error("exportGraph(): " + wsi4.util.translate("ErrorWritingFile"));
						return;
					}
					return;
				})();
				(() => {
					if (!exportOptionSet("twoDimGeoCutting")) {
						return;
					}
					const scene = sceneForVertex(vertex, {
						tubeCuttingShowTubeContours: true,
						tubeCuttingShowVirtualCuts: false,
					});
					const content = wsi4.geo.util.renderScene(scene, FileType.geo, {});
					if (content === undefined) {
						return wsi4.throwError("Cannot create file content");
					}
					const geoPath = writeFile(globalProcessDir, articleName, "geo", content);
					if (geoPath === undefined) {
						wsi4.util.error("exportGraph(): " + wsi4.util.translate("ErrorWritingFile") + ": " + (geoPath === undefined ? "undef" : geoPath));
						return;
					}
					if (exportOptionSet("createArticleDir")) {
						const linkPath = symlink(geoPath, articleProcessDir);
						if (linkPath === undefined) {
							wsi4.util.error("exportGraph(): " + wsi4.util.translate("ErrorCreatingLink"));
							return;
						}
					}
					return;
				})();
			} else if (twoDimRep !== undefined && exportOptionSet("twoDimSvg")) {
				const scene = defaultSceneForVertex(vertex);
				const content = wsi4.geo.util.renderScene(scene, FileType.svg, {});
				const path = writeFile(imagesSubDir, wsi4.util.toKey(vertex), "svg", content);
				if (path === undefined) {
					wsi4.util.error("exportGraph(): " + wsi4.util.translate("ErrorWritingFile") + ": " + (path === undefined ? "undef" : path));
				}
			}
		}

		// Writing png of assembly OR inputAssembly (if any)
		(() => {
			if (!exportOptionSet("threeDimPng")) {
				return;
			}
			const assembly = (wsi4.node.assembly(vertex) !== undefined ? wsi4.node.assembly(vertex) : wsi4.node.inputAssembly(vertex));
			if (assembly === undefined) {
				return;
			}
			const content = renderDefaultPng(assembly);
			if (content === undefined) {
				return wsi4.throwError("exportGraph(): Cannot create file content");
			}
			const path = writeFile(imagesSubDir, wsi4.util.toKey(vertex), "png", content);
			if (path === undefined) {
				wsi4.util.error("exportGraph(): " + wsi4.util.translate("ErrorWritingFile"));
				return;
			}
			return;
		})();
		(() => {
			const future = gltfFutures.find((vertexAndFuture: VertexAnd<ArrayBufferFuture>) => isEqual(vertexAndFuture.vertex, vertex));
			if (future === undefined) {
				return;
			}
			if (!exportOptionSet("threeDimHtml")) {
				return;
			}
			const path = exportThreeDimHtml(createPath(globalProcessDir, articleName), vertex, getFutureResult<"arrayBuffer">(future.data));
			if (path === undefined) {
				wsi4.util.error(wsi4.util.translate("ErrorWritingFile"));
				return;
			}
			if (exportOptionSet("createArticleDir")) {
				const linkPath = symlink(path, articleProcessDir);
				if (linkPath === undefined) {
					wsi4.util.error(wsi4.util.translate("ErrorCreatingLink"));
				}
			}
		})();
		(() => {
			if (!exportOptionSet("joiningInstructions")) {
				return;
			}
			if (wsi4.node.workStepType(vertex) !== "joining") {
				return;
			}
			const path = exportJoiningView(createPath(globalProcessDir, articleName), vertex);
			if (path === undefined) {
				wsi4.util.error(wsi4.util.translate("ErrorWritingFile"));
				return;
			}
			if (exportOptionSet("createArticleDir")) {
				const linkPath = symlink(path, articleProcessDir);
				if (linkPath === undefined) {
					wsi4.util.error(wsi4.util.translate("ErrorCreatingLink"));
				}
			}
		})();
		(() => {
			if (!exportOptionSet("coatingDetails")) {
				return;
			}
			if (!isSubProcess(ProcessType.coating, wsi4.node.processType(vertex))) {
				return;
			}
			const content = wsi4.documentCreator.renderIntoPdf(createCoatingDetails(vertex), {orientation: DocumentOrientation.portrait});
			const path = writeFile(globalProcessDir, articleName + "_details", "pdf", content);
			if (path === undefined) {
				wsi4.util.error(wsi4.util.translate("ErrorWritingFile"));
				return;
			}
			if (exportOptionSet("createArticleDir")) {
				const linkPath = symlink(path, articleProcessDir);
				if (linkPath === undefined) {
					wsi4.util.error(wsi4.util.translate("ErrorWritingFile"));
					return;
				}
			}
		})();
	};

	const exportArticleData = (cleanExportBaseDirPath: string, cleanDirPath: string, article: Array<Vertex>) => {
		(() => {
			if (!exportOptionSet("jobCards")) {
				return;
			}
			{
				const globalJobCardDir = createPath(cleanExportBaseDirPath, wsi4.util.translate("JobCards"));
				const documentRows = createJobCard(article);
				const pdfBa = wsi4.documentCreator.renderIntoPdf(documentRows, {orientation: DocumentOrientation.portrait});
				const workingPaperPath = writeFile(globalJobCardDir, computeElidedArticleName(article[0]!), "pdf", pdfBa);
				if (workingPaperPath === undefined) {
					wsi4.util.error("exportArticleData(): " + wsi4.util.translate("ErrorWritingFile"));
					return;
				}
				if (exportOptionSet("createArticleDir")) {
					const linkPath = symlink(workingPaperPath, cleanDirPath);
					if (linkPath === undefined) {
						wsi4.util.error(wsi4.util.translate("ErrorWritingFile"));
						return;
					}
				}
			}
			return;
		})();
		(() => {
			if (!exportOptionSet("jobCardsDocx")) {
				return;
			}
			{
				const jobCardData = createJobCardData(article);
				if (jobCardData === undefined) {
					return;
				}
				const path = readSetting("jobCardTemplatePath");
				const tmpl = wsi4.io.fs.readFile(path === "" ? ":/templates/jobcard.docx" : path);
				if (tmpl === undefined) {
					wsi4.util.error("Error reading jobcard template.");
					return;
				}
				const docxBa = createJobCardDocx(tmpl, jobCardData);
				if (docxBa === undefined) {
					return;
				}
				const globalJobCardDir = createPath(cleanExportBaseDirPath, wsi4.util.translate("JobCards"));
				const workingPaperPath = writeFile(globalJobCardDir, computeElidedArticleName(article[0]!), "docx", docxBa);
				if (workingPaperPath === undefined) {
					wsi4.util.error("exportArticleData(): " + wsi4.util.translate("ErrorWritingFile"));
					return;
				}
				if (exportOptionSet("createArticleDir")) {
					const linkPath = symlink(workingPaperPath, cleanDirPath);
					if (linkPath === undefined) {
						wsi4.util.error(wsi4.util.translate("ErrorWritingFile"));
						return;
					}
				}
			}
			return;
		})();

		(() => {
			if (!exportOptionSet("subGraphs")) {
				return;
			}

			const component = wsi4.graph.undirectedConnectedComponents()
				.find(vertices => vertices.some(vertex => isEqual(vertex, article[0])));
			assert(component !== undefined, "Expecting associated sub-graph");

			// Picking one vertex as the "representative" terminal vertex of the graph component
			const terminalVertex = component.filter(v => wsi4.graph.targets(v).length === 0)
				.sort((lhs, rhs) => wsi4.util.toNumber(lhs) - wsi4.util.toNumber(rhs))
				.shift();
			assert(terminalVertex !== undefined, "Expecting terminal vertex in graph component");

			const subGraphsDir = createPath(cleanExportBaseDirPath, cleanRelativeDirPath(wsi4.util.translate("sub_graphs")));
			const filePath = createPath(subGraphsDir, computeElidedArticleName(terminalVertex), "wsi4");

			if (!wsi4.io.fs.exists(filePath)) {
				wsi4.io.fs.mkpath(subGraphsDir);
				const buffer = serializeUndirectedConnectedComponent(terminalVertex);
				const success = wsi4.io.fs.writeFile(filePath, buffer);
				if (!success) {
					wsi4.util.error("exportArticleData(): " + wsi4.util.translate("ErrorWritingFile"));
					return;
				}
			}

			if (exportOptionSet("createArticleDir")) {
				const linkPath = symlink(filePath, cleanDirPath);
				if (linkPath === undefined) {
					wsi4.util.error(wsi4.util.translate("ErrorWritingFile"));
				}
			}
		})();

		for (const v of article) {
			exportNodeData(cleanExportBaseDirPath, createPath(cleanDirPath, wsi4.util.translate("ExportWorkSteps")), v);
		}
		return;
	};

	const exportArticles = function(cleanExportBaseDirPath: string, cleanDirPath: string) {
		const articles = wsi4.graph.articles();
		for (const article of articles) {
			exportArticleData(cleanExportBaseDirPath, createPath(cleanDirPath, computeElidedArticleName(article[0]!)), article);
		}
	};

	const exportGraphData = function(cleanDirPath: string) {
		const graphAttachments = (() => {
			const a = getGraphUserDataEntry("attachments");
			return a === undefined ? [] : a;
		})();
		const graphAttachmentsDir = createPath(cleanDirPath, wsi4.util.translate("attachments"));
		for (const attachment of graphAttachments) {
			const path = writeFile(graphAttachmentsDir, attachment.name, "", wsi4.util.fromBase64(wsi4.util.stringToArrayBuffer(attachment.data)));
			if (path === undefined) {
				wsi4.util.error(wsi4.util.translate("exportGraphData(): ErrorWritingFile"));
			}
		}
		const subDirectory = createPath(cleanDirPath, wsi4.util.translate("Articles"));
		exportArticles(cleanDirPath, subDirectory);
	};

	exportGraphData(cleanExportDirPath);
}

function computeDateString() {
	const date = new Date();
	return `${date.getFullYear()}-${date.getMonth()}-${date.getDay()}`;
}

const lastExportDateSettingsKey = "gui_export_last_date";

function isNumExportsExceeded(): boolean {
	return legacyReadSetting(lastExportDateSettingsKey, "", isString) === computeDateString();
}

function writeLastExportDate(): void {
	writeSetting(lastExportDateSettingsKey, computeDateString());
}

function continueExport(): boolean {
	if (wsi4.isFeatureEnabled("unlimitedNumExports")) {
		return true;
	} else if (isNumExportsExceeded()) {
		showInfo(
			wsi4.util.translate("demo_version"),
			wsi4.util.translate("num_exports_exceeded_message!"),
		);
		return false;
	} else {
		const shouldProceed = askQuestion(
			wsi4.util.translate("demo_version"),
			wsi4.util.translate("num_exports_limited_continue?"),
		);
		if (shouldProceed) {
			writeLastExportDate();
			return true;
		} else {
			return false;
		}
	}
}

export function runGuiExport(): void {
	// Check if graph is empty
	if (wsi4.graph.vertices().length === 0) {
		// Nothing to do
		return;
	}

	if (wsi4.graph.vertices()
		.some(v => !isExportReady(v, guiReplyStateLevelMap, guiConstraintLevelMap))) {
		showError(wsi4.util.translate("export_failed"), wsi4.util.translate("graph_not_export_ready"));
		return;
	}

	if (!continueExport()) {
		return;
	}

	// Setup export directory (get path and delete existing dir if any)
	const exportPath = (() => {
		let basePath = legacyReadSetting("last_export_base_dir", "", isString);
		if (typeof basePath !== "string") {
			return undefined;
		}
		{
			const path = getDirectoryPath(wsi4.util.translate("ExportDirectory"), basePath);
			if (typeof path !== "string") {
				return undefined;
			}
			basePath = path;
		}

		const name = (() => {
			const result = computeElidedName(projectName());
			if (!result || !result.length || result.length === 0) {
				// Note: unexpected.
				// An empty document graph should be detected at beginning of export so this is not reached in this case.
				return wsi4.util.translate("Unknown");
			}
			return result;
		})();

		const proposal = createPath(basePath, name);
		if (wsi4.io.fs.exists(proposal)) {
			const yes = askQuestion(wsi4.util.translate("OverwriteDirectoryTitle"), wsi4.util.translate("OverwriteDirectoryQuestion") + "\n\n" + proposal);
			if (!yes) {
				return undefined;
			}
			if (!wsi4.io.fs.rm(proposal)) {
				showError(wsi4.util.translate("ErrorOverwritingExportDir"), wsi4.util.translate("ErrorOverwritingExportDir") + "\n\n" + wsi4.util.translate("FixExportDir"));
				return undefined;
			}
		}
		writeSetting("last_export_base_dir", basePath);
		return proposal;
	})();

	if (exportPath === undefined) {
		// Expected errors are handled on demand (e. g. if export dir cannot be overwritten)
		return;
	}

	wsi4.util.info(wsi4.util.translate("InfoExportingGraph"));
	exportGraph(exportPath, createGltfFutures(wsi4.graph.vertices()));
	wsi4.util.info(wsi4.util.translate("InfoDone"));

	if (exportOptionSet("calculation")) {
		wsi4.util.info(wsi4.util.translate("InfoCreatingCalculation"));
		const subDirectory = createPath(exportPath, wsi4.util.translate("Calculation"));
		const documentRows = createInternalCalc();
		const pdfBa = wsi4.documentCreator.renderIntoPdf(documentRows, {orientation: DocumentOrientation.portrait});
		writeFile(subDirectory, wsi4.util.translate("Calculation"), "pdf", pdfBa);
		wsi4.util.info(wsi4.util.translate("InfoDone"));
	}

	(() => {
		if (!exportOptionSet("quotation")) {
			return;
		}
		const quotationInput = createQuotationInput();
		if (quotationInput === undefined) {
			return;
		}
		wsi4.util.info(wsi4.util.translate("InfoCreatingQuotation"));
		const path = readSetting("quotationTemplatePath");
		const tmpl = wsi4.io.fs.readFile(path === "" ? ":/templates/quotation.docx" : path);
		if (tmpl === undefined) {
			wsi4.util.error("Error reading quotation template.");
			return;
		}
		const docxBa = createQuotationDocx(tmpl, quotationInput);
		if (docxBa === undefined) {
			return;
		}
		const subDirectory = createPath(exportPath, wsi4.util.translate("Calculation"));
		writeFile(subDirectory, wsi4.util.translate("Quotation"), "docx", docxBa);
		wsi4.util.info(wsi4.util.translate("InfoDone"));
	})();

	if (exportOptionSet("erpInputData")) {
		const graphJson = (() => {
			if (wsi4.isFeatureEnabled("graphRepExport")) {
				const scaleDataConfig: ScaleDataConfig = (() => {
					const calcSettings = readCalcSettings();
					switch (calcSettings.scaleValueMode) {
						case "none": return {
							type: "none",
						};
						case "relative": return {
							type: "relativeValues",
							values: calcSettings.baseScaleValues,
						};
						case "absolute": return {
							type: "absoluteValues",
							values: calcSettings.baseScaleValues,
						};
					}
				})();
				const pngFutures = createPngFutures(wsi4.graph.vertices());
				const graphRep = createGraphRepresentation(scaleDataConfig, pngFutures);
				return JSON.stringify(graphRep);
			} else {
				return wsi4.util.translate("graph_rep_export_is_liable_to_pay");
			}
		})();
		writeFile(exportPath, "graph", "json", wsi4.util.stringToArrayBuffer(graphJson));
	}

	if (exportOptionSet("bomCsv")) {
		const bomCsv = (() => {
			if (wsi4.isFeatureEnabled("bomExport")) {
				const bomEntries = wsi4.graph.articles()
					.filter(article => isComponentArticle(article))
					.map((article, index) => createBomEntry(article, index));
				return createBomCsv(bomEntries, getSettingOrDefault("csvLocale"));
			} else {
				return wsi4.util.translate("bom_export_is_liable_to_pay");
			}
		})();
		writeFile(exportPath, "bom", "csv", wsi4.util.stringToArrayBuffer(bomCsv));
	}

	wsi4.util.info(wsi4.util.translate("InfoExportFinished"));
}
