/**
 * Typesafe wrapper for Article UserData
 */

import {
	isStringIndexedInterface,
} from "qrc:/js/lib/generated/typeguard";
import {
	assertDebug,
	isString,
} from "./utils";

/**
 * UserData common for all articles
 */
export interface ArticleUserData {
	/**
	 * Article name
	 *
	 * User editable name that might be pre-set by us.
	 */
	name: string;

	/**
	 * Article specific comment
	 *
	 * Empty by default.
	 */
	comment: string;

	/**
	 * User-defined / thirdparty part number
	 *
	 * ("Artikelnummer")
	 *
	 * Note: There are no guarantees for this value to be unique.
	 */
	externalPartNumber: string;

	/**
	 * User-defined / thirdparty drawing number
	 *
	 * ("Zeichnungsnummer")
	 *
	 * Note: There are no guarantees for this value to be unique.
	 */
	externalDrawingNumber: string;

	/**
	 * User-defined / thirdparty revision number
	 *
	 * ("Revisionsnummer")
	 *
	 * Note: There are no guarantees for this value to be unique.
	 */
	externalRevisionNumber: string;

	/**
	 * Sub-section for custom UserData
	 */
	customUserData: StringIndexedInterface;
}

const articleUserDataTypeGuards: {[Key in keyof ArticleUserData]: (arg: unknown) => arg is ArticleUserData[Key]} = {
	name: isString,
	comment: isString,
	externalPartNumber: isString,
	externalDrawingNumber: isString,
	externalRevisionNumber: isString,
	customUserData: isStringIndexedInterface,
};

function isArticleUserDatum<Key extends keyof ArticleUserData>(key: Key, value: unknown): value is ArticleUserData[Key] {
	return articleUserDataTypeGuards[key](value);
}

/**
 * Type-casting abstraction for common article user data.
 */
export function articleUserDatumImpl<Key extends keyof ArticleUserData>(key: Key, userData: StringIndexedInterface): ArticleUserData[Key] | undefined {
	const value = userData[key];
	if (value === undefined || value === null) {
		return undefined;
	}

	// This is not expected - there should always be a proper migration in case the underlying data change.
	// Hence, running the check only in debug mode.
	assertDebug(() => isArticleUserDatum(key, value), "Article user datum inconsistent for key " + key + ": " + JSON.stringify(value));

	return value as ArticleUserData[Key];
}

/**
 * Type-checked update of common Article UserData
 */
export function createUpdatedArticleUserData<Key extends keyof ArticleUserData>(key: Key, value: ArticleUserData[Key], userData: StringIndexedInterface): StringIndexedInterface {
	userData[key] = value;
	return userData;
}

export function articleUserDatum<Key extends keyof ArticleUserData>(key: Key, vertex: Vertex): ArticleUserData[Key] | undefined {
	const userData = wsi4.node.articleUserData(vertex);
	return articleUserDatumImpl(key, userData);
}
