
namespace _zeitbild.conf
{
	
	/**
	 */
	type type_log_threshold = (
		"debug"
		|
		"info"
		|
		"notice"
		|
		"warning"
		|
		"error"
	);
	
	
	/**
	 */
	type type_log_format = (
		"jsonl"
		|
		"human_readable"
	);
	
	
	/**
	 */
	export type type_conf = {
		general : {
			language : (null | string);
		};
		log : Array<
			{
				kind : "stdout";
				data : {
					threshold : type_log_threshold;
				};
			}
			|
			{
				kind : "file";
				data : {
					threshold : type_log_threshold;
					path : string;
				};
			}
			|
			{
				kind : "email";
				data : {
					threshold : type_log_threshold;
					smtp_credentials : {
						host : string;
						port : int;
						username : string;
						password : string;
					};
					sender : string;
					receivers : Array<string>;
				};
			}
		>;
		server : {
			host : string;
			port : int;
			path_base : string;
		};
		database : (
			{
				kind : "sqlite";
				data : {
					path : string;
				};
			}
			|
			{
				kind : "postgresql";
				data : {
					host : string;
					port ?: int;
					username : string;
					password : string;
					schema : string;
				};
			}
		);
		authentication : (
			{
				kind : "internal";
				data : {
				};
			}
			|
			{
				kind : "oidc";
				data : {
					client_id : string;
					client_secret : string;
					url_authorization : string;
					url_token : string;
					url_userinfo : string;
				};
			}
		);
		session_management : {
			in_memory : boolean;
			drop_all_at_start : boolean;
			lifetime : int;
		};
	};
	
	
	/**
	 */
	var _data : (null | type_conf) = null;
	
	
	/**
	 */
	export function inject(
		conf_raw : any
	) : void
	{
		const version : int = (conf_raw["version"] ?? 1);
		_data = {
			"general": (
				((node_general) => ({
					"language": (node_general["language"] ?? null),
				})) (conf_raw["general"] ?? {})
			),
			"log": (
				(() => {
					const node_log = (
						conf_raw["log"]
						??
						[
							{
								"kind": "stdout",
								"data": {
								}
							},
						]
					);
					return (
						node_log.map(
							(node_log_entry : any) => ({
								"kind": node_log_entry["kind"],
								"data": Object.assign(
									{
										"format": "human_readable",
										"threshold": "notice",
									},
									(node_log_entry["data"] ?? {})
								)
							})
						)
					);
				}) ()
			),
			"server": (
				((node_server) => ({
					"host": (() => {
						return (node_server["host"] ?? "::");
					}) (),
					"port": (node_server["port"] ?? 7845),
					"path_base": (node_server["path_base"] ?? ""),
				})) (conf_raw["server"] ?? {})
			),
			"database": (
				((node_database) => {
					const kind : string = (node_database["kind"] ?? "sqlite");
					const node_database_data_raw = (node_database["data"] ?? {});
					switch (kind) {
						case "sqlite": {
							return {
								"kind": kind,
								"data": {
									"path": (node_database_data_raw["path"] ?? "data.sqlite"),
								}
							};
							break;
						}
						case "postgresql": {
							return {
								"kind": kind,
								"data": node_database_data_raw,
							};
							break;
						}
						default: {
							throw (new Error("unhandled"));
							break;
						}
					}
				}) (conf_raw["database"] ?? {})
			),
			"session_management": (
				((node_session_management) => ({
					"in_memory": (node_session_management["in_memory"] ?? true),
					"drop_all_at_start": (node_session_management["drop_all_at_start"] ?? true),
					"lifetime": (node_session_management["lifetime"] ?? 900),
				})) (conf_raw["session_management"] ?? {})
			),
		};
	}
	
	
	/**
	 * @todo mandatory fields
	 */
	export async function load(
		path : string
	) : Promise<void>
	{
		let conf_raw : any;
		if (! (await lib_plankton.file.exists(path))) {
			// return Promise.reject<void>(new Error("configuration file not found: " + path + "; using fallback"));
			conf_raw = {};
		}
		else {
			try {
				conf_raw = lib_plankton.json.decode(await lib_plankton.file.read(path));
			}
			catch (error) {
				conf_raw = null;
			}
		}
		if (conf_raw === null) {
			return Promise.reject<void>("configuration file could not be read");
		}
		else {
			inject(conf_raw);
			// process.stderr.write(JSON.stringify(_data, undefined, "\t"));
			return Promise.resolve<void>(undefined);
		}
	}
	
	
	/**
	 */
	export function get(
	) : type_conf
	{
		if (_data === null) {
			throw (new Error("conf not loaded yet"));
		}
		else {
			return _data;
		}
	}
	
}
