/*
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Backend
Copyright (C) 2024 Christian Fraß

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public 
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later 
version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied 
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see 
<https://www.gnu.org/licenses/>. 
 */

namespace _espe.conf
{
	
	/**
	 */
	export type type_conf = {
		general : {
			verbosity : (
				"none"
				|
				"debug"
				|
				"notice"
				|
				"info"
				|
				"warning"
				|
				"error"
			);
			verification_secret : (null | string);
		};
		server : {
			port : int;
			path_base : string;
		};
		database : (
			{
				kind : "sqlite";
				data : {
					path : string;
				};
			}
			|
			{
				kind : "postgresql";
				data : {
					host : string;
					port ?: int;
					username : string;
					password : string;
					schema : string;
				};
			}
		);
		email_sending : (
			{
				kind : "regular";
				data : {
					smtp_credentials : _espe.helpers.type_smtp_credentials;
					sender : string;
				};
			}
			|
			{
				kind : "redirect";
				data : {
					smtp_credentials : _espe.helpers.type_smtp_credentials;
					sender : string;
					target : string;
				};
			}
			|
			{
				kind : "console";
				data : {
				};
			}
			|
			{
				kind : "drop";
				data : {
				};
			}
		);
		session_management : {
			in_memory : boolean;
			drop_all_at_start : boolean;
			lifetime : int;
		};
		settings : {
			target_domain : string;
			frontend_url_base : (null | string);
			login_url : (null | string);
			prefix_for_nominal_email_addresses : string;
			facultative_membership_number : boolean;
			summon_email : {
				subject : string;
				body : string;
			};
			registration_email : {
				subject : string;
				body : string;
			};
			activation_email : {
				subject : string;
				body : string;
			};
			password_policy : {
				minimum_length : (null | int);
				maximum_length : (null | int);
				must_contain_letter : boolean;
				must_contain_number : boolean;
				must_contain_special_character : boolean;
			};
			password_change : {
				cooldown_time : int;
				initialization_email : {
					subject : string;
					body : string;
				};
				execution_email : {
					subject : string;
					body : string;
				};
			};
			name_index : {
				veil : boolean;
				salt : (null | string);
			};
		};
		// TODO: evtl. in Datenbank verlagern
		admins : Array<
			{
				name : string;
				password_image : string;
				email_address : (null | string);
			}
		>;
		output : {
			authelia : (null | string);
		};
	};
	
	
	/**
	 */
	var _data : (null | type_conf) = null;
	
	
	/**
	 */
	export function inject(
		conf_raw : any
	) : void
	{
		_data = {
			"general": (
				((node_general) => ({
					"verbosity": (node_general["verbosity"] ?? "notice"),
					"verification_secret": (node_general["verification_secret"] ?? null),
				})) (conf_raw["general"] ?? {})
			),
			"server": (
				((node_server) => ({
					"port": (node_server["port"] ?? 7979),
					"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"] ?? {})
			),
			"email_sending": (
				((node_email_sending) => {
					const kind : string = (node_email_sending["kind"] ?? "regular");
					const data_raw = (node_email_sending["data"] ?? {});
					switch (kind) {
						case "regular": {
							return {
								"kind": kind,
								"data": {
									"smtp_credentials": (data_raw["smtp_credentials"] ?? null),
									"sender": data_raw["sender"],
								}
							};
							break;
						}
						case "redirect": {
							return {
								"kind": kind,
								"data": {
									"smtp_credentials": (data_raw["smtp_credentials"] ?? null),
									"sender": data_raw["sender"],
									"target": data_raw["target"],
								}
							};
							break;
						}
						case "console": {
							return {
								"kind": kind,
								"data": {
								}
							};
							break;
						}
						case "drop": {
							return {
								"kind": kind,
								"data": {
								}
							};
							break;
						}
						default: {
							throw (new Error("unhandled"));
							break;
						}
					}
				}) (conf_raw["email_sending"] ?? {})
			),
			"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"] ?? {})
			),
			"settings": (
				((node_settings) => ({
					"target_domain": (node_settings["target_domain"] ?? "example.org"),
					"frontend_url_base": (node_settings["frontend_url_base"] ?? null), // TODO: mandatory?
					"login_url": (node_settings["login_url"] ?? null),
					"prefix_for_nominal_email_addresses": (node_settings["prefix_for_nominal_email_addresses"] ?? "member-"),
					"facultative_membership_number": (node_settings["facultative_membership_number"] ?? false),
					"summon_email": {
						"subject": ((node_settings["summon_email"] ?? {})["subject"] ?? "Please register"),
						"body": ((node_settings["summon_email"] ?? {})["body"] ?? "URL: {{url}}"),
					},
					"registration_email": {
						"subject": ((node_settings["registration_email"] ?? {})["subject"] ?? "Mmeber registered"),
						"body": ((node_settings["registration_email"] ?? {})["body"] ?? "URL: {{url}}"),
					},
					"activation_email": {
						"subject": ((node_settings["activation_email"] ?? {})["subject"] ?? "Account activated"),
						"body": ((node_settings["activation_email"] ?? {})["body"] ?? "URL: {{url}}\n\nLogin name: {{name_login}}\n\n"),
					},
					"password_policy": (
						((node_settings_password_policy) => ({
							"minimum_length": (
								("minimum_length" in node_settings_password_policy)
								? node_settings_password_policy["minimum_length"]
								: 8
							),
							"maximum_length": (
								("maximum_length" in node_settings_password_policy)
								? node_settings_password_policy["maximum_length"]
								: 240
							),
							"must_contain_letter": (node_settings_password_policy["must_contain_letter"] ?? true),
							"must_contain_number": (node_settings_password_policy["must_contain_number"] ?? true),
							"must_contain_special_character": (node_settings_password_policy["must_contain_special_character"] ?? true),
						})) (node_settings["password_policy"] ?? {})
					),
					"password_change": (
						((node_settings_password_change) => ({
							"cooldown_time": (node_settings_password_change["cooldown_time"] ?? 86400),
							"initialization_email": {
								"subject": ((node_settings_password_change["initialization_email"] ?? {})["subject"] ?? "Password change initialized"),
								"body": ((node_settings_password_change["initialization_email"] ?? {})["body"] ?? "{{url}}"),
							},
							"execution_email": {
								"subject": ((node_settings_password_change["execution_email"] ?? {})["subject"] ?? "Password changed"),
								"body": ((node_settings_password_change["execution_email"] ?? {})["body"] ?? ""),
							},
						})) (node_settings["password_change"] ?? {})
					),
					"name_index": (
						((node_settings_password_policy) => ({
							"veil": (node_settings_password_policy["veil"] ?? false),
							"salt": (node_settings_password_policy["salt"] ?? null),
						})) (node_settings["name_index"] ?? {})
					),
				})) (conf_raw["settings"] ?? {})
			),
			"admins": (conf_raw["admins"] ?? []),
			"output": (
				((node_session_output) => ({
					"authelia": (node_session_output["authelia"] ?? null),
				})) (conf_raw["output"] ?? {})
			),
		};
	}
	
	
	/**
	 * @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;
		}
	}
	
}
