import {
	DocumentAlignment,
	DocumentImageType,
	DocumentItemType,
	TableType,
} from "qrc:/js/lib/generated/enum";
import {
	isStringIndexedInterface,
} from "qrc:/js/lib/generated/typeguard";
import {
	getArticleName,
} from "qrc:/js/lib/graph_utils";
import {
	createLineEditRow,
	createTextEditRow,
} from "qrc:/js/lib/gui_form_widget";
import {
	showError,
	showFormWidget,
} from "qrc:/js/lib/gui_utils";
import {
	finalVertex,
} from "qrc:/js/lib/node_utils";
import {
	getTable,
} from "qrc:/js/lib/table_utils";
import {
	assert,
	getKeysOfObject,
	isString,
	readSetting,
	writeSetting,
} from "qrc:/js/lib/utils";
import {
	front,
} from "qrc:/js/lib/array_util";

import {
	computeProjectSellingPrice,
} from "./export_calc_costs";
import {
	getFixedMultiplicity,
} from "./export_calc_times";
import {
	createHeading,
	createImageItem,
	createSpacerItem,
	createTitle,
	currencyString,
} from "./export_utils";

function createFirstPageHeader(): Array<Array<DocumentItem>> {
	return createTitle(wsi4.util.translate("Quotation"));
}

declare interface InputRequestResult {
	senderAddress: string;
	receiverAddress: string;
	customerId: string;
	quotationId: string;
	quotationTextBegin: string;
	quotationTextEnd: string;
}
export function isInputRequestResult(arg: unknown): arg is InputRequestResult {
	const obj: InputRequestResult = {
		senderAddress: "",
		receiverAddress: "",
		customerId: "",
		quotationId: "",
		quotationTextBegin: "",
		quotationTextEnd: "",
	};
	return isStringIndexedInterface(arg) && getKeysOfObject(obj)
		.every(key => isString(arg[key]));
}

function createAddressBlock(inputRequestResult: InputRequestResult): Array<Array<DocumentItem>> {
	const senderAddress = "<small>" + inputRequestResult.senderAddress + "</small>";
	const receiverAddress = String(inputRequestResult.receiverAddress)
		.replace(/\n/giu, "<br>");
	return [
		[ createSpacerItem(12) ],
		[ createSpacerItem(12) ],
		[
			{
				type: DocumentItemType.paragraph,
				content: {
					width: 6,
					text: senderAddress,
					alignment: DocumentAlignment.left,
				},
			},
			createSpacerItem(6),
		],
		[
			{
				type: DocumentItemType.paragraph,
				content: {
					width: 6,
					text: receiverAddress,
					alignment: DocumentAlignment.left,
				},
			},
			createSpacerItem(6),
		],
	];
}

function createDataBlock(inputRequestResult: InputRequestResult): Array<Array<DocumentItem>> {
	const tableItem = {
		type: DocumentItemType.table,
		content: {
			width: 3,
			alignment: DocumentAlignment.right,
			columnWidths: [ 100 ],
			columnHeaders: [],
			rows: [
				[
					{
						text: "<small>" + wsi4.util.translate("CustomerId") + "</small>",
						alignment: DocumentAlignment.left,
					},
				],
				[
					{
						text: "<small>" + inputRequestResult.customerId + "</small>",
						alignment: DocumentAlignment.right,
					},
				],
				[
					{
						text: "<small>" + wsi4.util.translate("QuotationId") + "</small>",
						alignment: DocumentAlignment.left,
					},
				],
				[
					{
						text: "<small>" + inputRequestResult.quotationId + "</small>",
						alignment: DocumentAlignment.right,
					},
				],
				[
					{
						text: "<small>" + wsi4.util.translate("Date") + "</small>",
						alignment: DocumentAlignment.left,
					},
				],
				[
					{
						text: new Date()
							.toLocaleDateString(undefined, {
								year: "numeric",
								month: "long",
								day: "numeric",
							}),
						alignment: DocumentAlignment.right,
					},
				],
			],
		},
	};

	return [
		[
			createSpacerItem(9),
			tableItem,
		],
	];
}

function createIntroBlock(inputRequestResult: InputRequestResult): Array<Array<DocumentItem>> {
	return [
		[
			{
				type: DocumentItemType.paragraph,
				content: {
					width: 12,
					text: String(inputRequestResult.quotationTextBegin)
						.replace(/\n/giu, "<br>"),
					alignment: DocumentAlignment.left,
				},
			},
		],
	];
}

function createPositionsBlock(): Array<Array<DocumentItem>> {
	const rows = wsi4.graph.articles()
		.reduce(
			(outerAcc: Array<DocumentTableRow>, article, index) => {
				if (article.length === 0) {
					console.warn("Skipping empty article");
					return outerAcc;
				}
				const multiplicity = getFixedMultiplicity(front(article));
				outerAcc = [
					...outerAcc,
					[
						// Adding 1 for 1-based indexing
						{
							text: Number(index + 1)
								.toString(),
							alignment: DocumentAlignment.right,
						},
						{
							text: /* spacer */ "",
							alignment: DocumentAlignment.left,
						},
						{
							text: Number(multiplicity)
								.toString(),
							alignment: DocumentAlignment.right,
						},
						{
							text: /* spacer */ "",
							alignment: DocumentAlignment.left,
						},
						{
							text: getArticleName(front(article)),
							alignment: DocumentAlignment.left,
						},
						{
							text: "",
							alignment: DocumentAlignment.left,
						},
					],
				];
				const table = getTable(TableType.process);
				return article.reduce((innerAcc, vertex) => {
					const processId = wsi4.node.processId(vertex);
					const row = table.find(element => element.identifier === processId);
					if (row === undefined) {
						wsi4.throwError("Table invalid");
					}
					const processName = row.name === undefined ? wsi4.util.translate("Unknown") : row.name;
					return [
						...innerAcc,
						[
							{
								text: "",
								alignment: DocumentAlignment.left,
							},
							{
								text: /* spacer */ "",
								alignment: DocumentAlignment.left,
							},
							{
								text: /* spacer */ "",
								alignment: DocumentAlignment.left,
							},
							{
								text: /* spacer */ "",
								alignment: DocumentAlignment.left,
							},
							{
								text: "",
								alignment: DocumentAlignment.left,
							},
							{
								text: processName,
								alignment: DocumentAlignment.left,
							},
						],
					];
				}, outerAcc);
			},
			[
				// table header
				[
					{
						text: wsi4.util.translate("QuotationItem"),
						alignment: DocumentAlignment.left,
					},
					{
						text: /* spacer */ "",
						alignment: DocumentAlignment.left,
					},
					{
						text: wsi4.util.translate("Multiplicity"),
						alignment: DocumentAlignment.left,
					},
					{
						text: /* spacer */ "",
						alignment: DocumentAlignment.left,
					},
					{
						text: wsi4.util.translate("Name"),
						alignment: DocumentAlignment.left,
					},
					{
						text: wsi4.util.translate("QuotationWorkStep"),
						alignment: DocumentAlignment.left,
					},
				],
			]);

	return [
		createHeading(wsi4.util.translate("QuotationItems"), 4),
		[
			{
				type: DocumentItemType.table,
				content: {
					width: 12,
					alignment: DocumentAlignment.left,
					columnWidths: [
						10,
						5,
						10,
						5,
						40,
						30,
					],
					columnHeaders: [],
					rows: rows,
				},
			},
		],
	];
}

function createAssemblyImage(): Array<Array<DocumentItem>> {
	const vertex = finalVertex();
	if (vertex === undefined) {
		wsi4.util.error("addAssemblyImage(): There is no final graph node. Skipping symbolic image in quotation.");
		return [];
	}
	return [
		[
			{
				type: DocumentItemType.paragraph,
				content: {
					width: 3,
					text: /* spacer */ "",
					alignment: DocumentAlignment.left,
				},
			},
			createImageItem(vertex, DocumentImageType.png, 6, DocumentAlignment.center),
			{
				type: DocumentItemType.paragraph,
				content: {
					width: 3,
					text: /* spacer */ "",
					alignment: DocumentAlignment.left,
				},
			},
		],
		[
			{
				type: DocumentItemType.paragraph,
				content: {
					width: 12,
					text: "<small>" + wsi4.util.translate("ImageSimilar") + "</small>",
					alignment: DocumentAlignment.center,
				},
			},
		],
	];
}

function createSellingPriceBlock(): Array<Array<DocumentItem>> {
	const sellingPrice = computeProjectSellingPrice();
	if (sellingPrice === undefined) {
		showError(wsi4.util.translate("QuotationErrorTitle"), wsi4.util.translate("QuotationErrorText"));
		return [];
	}
	const tableItem = {
		type: DocumentItemType.table,
		content: {
			width: 12,
			alignment: DocumentAlignment.left,
			columnWidths: [
				50,
				50,
			],
			columnHeaders: [],
			rows: [
				[
					{
						text: wsi4.util.translate("OverallSellingPrice"),
						alignment: DocumentAlignment.left,
					},
					{
						text: currencyString(sellingPrice),
						alignment: DocumentAlignment.right,
					},
				],
			],
		},
	};
	return [
		createHeading(wsi4.util.translate("OverallPrice"), 3),
		[ tableItem ],
	];
}

// Document creation - quotation
function createOutroBlock(inputRequestResult: InputRequestResult): Array<Array<DocumentItem>> {
	return [
		[
			{
				type: DocumentItemType.paragraph,
				content: {
					width: 12,
					text: String(inputRequestResult.quotationTextEnd)
						.replace(/\n/giu, "<br>"),
					alignment: DocumentAlignment.left,
				},
			},
		],
	];
}

export function createQuotation(): Array<Array<DocumentItem>>|undefined {
	function createSettingsKey(key: string) {
		return "quotation_input_request_" + key;
	}

	const dialogResult = showFormWidget(
		[
			createLineEditRow(
				"senderAddress",
				wsi4.util.translate("SenderAddress"),
				readSetting(createSettingsKey("senderAddress"), wsi4.util.translate("DefaultSenderAddress"), isString),
			),
			createTextEditRow(
				"receiverAddress",
				wsi4.util.translate("ReceiverAddress"),
				readSetting(createSettingsKey("receiverAddress"), wsi4.util.translate("DefaultReceiverAddress"), isString),
			),
			createLineEditRow(
				"customerId",
				wsi4.util.translate("CustomerId"),
				readSetting(createSettingsKey("customerId"), "", isString),
			),
			createLineEditRow(
				"quotationId",
				wsi4.util.translate("QuotationId"),
				readSetting(createSettingsKey("quotationId"), "", isString),
			),
			createTextEditRow(
				"quotationTextBegin",
				wsi4.util.translate("QuotationTextBegin"),
				readSetting(createSettingsKey("quotationTextBegin"), wsi4.util.translate("DefaultQuotationTextBegin"), isString),
			),
			createTextEditRow(
				"quotationTextEnd",
				wsi4.util.translate("QuotationTextEnd"),
				readSetting(createSettingsKey("quotationTextEnd"), wsi4.util.translate("DefaultQuotationTextEnd"), isString),
			),
		],
	);

	if (dialogResult === undefined) {
		// User canceled
		return undefined;
	}

	const inputRequestResult = dialogResult.values;
	assert(isInputRequestResult(inputRequestResult));

	writeSetting(createSettingsKey("senderAddress"), inputRequestResult.senderAddress);
	writeSetting(createSettingsKey("receiverAddress"), inputRequestResult.receiverAddress);
	writeSetting(createSettingsKey("customerId"), inputRequestResult.customerId);
	writeSetting(createSettingsKey("quotationId"), inputRequestResult.quotationId);
	writeSetting(createSettingsKey("quotationTextBegin"), inputRequestResult.quotationTextBegin);
	writeSetting(createSettingsKey("quotationTextEnd"), inputRequestResult.quotationTextEnd);

	return [
		...createFirstPageHeader(),
		...createAddressBlock(inputRequestResult),
		...createDataBlock(inputRequestResult),
		...createIntroBlock(inputRequestResult),
		...createPositionsBlock(),
		...createAssemblyImage(),
		...createSellingPriceBlock(),
		...createOutroBlock(inputRequestResult),
	];
}
