/*
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.helpers
{
	
	/**
	 */
	export type type_smtp_credentials = {
		host : string;
		port : int;
		username : string;
		password : string;
	};
	
	
	/**
	 */
	/*
	export function yaml_encode(
		thing : any
	) : string
	{
	}
	 */
	
	
	/**
	 * @todo outsource
	 */
	export async function bcrypt_compute(
		input : string,
		options : {
			rounds ?: int;
		} = {}
	) : Promise<string>
	{
		options = Object.assign(
			{
				"rounds": 12,
			},
			options
		);
		const nm_bcrypt = require("bcrypt");
		const salt : string = await nm_bcrypt.genSalt(options.rounds)
		const result : string = await nm_bcrypt.hash(input, salt);
		return result;
	}
	
	
	/**
	 * @todo outsource
	 */
	export async function bcrypt_compare(
		password_shall_image : string,
		password_is : string
	) : Promise<boolean>
	{
		const nm_bcrypt = require("bcrypt");
		const result = await nm_bcrypt.compare(password_is, password_shall_image);
		return result;
	}
	
	
	/**
	 * @deprecated
	 */
	export function database_implementation(
	) : lib_plankton.database.type_database
	{
		return _espe.database.get_implementation();
	}
	
	
	/**
	 */
	export async function verification_get(
		data : any
	) : Promise<string>
	{
		const secret : (null | string) = _espe.conf.get().general.verification_secret;
		if (secret === null) {
			return Promise.reject<string>(new Error("no verification secret specified; add in conf as 'general.verification_secret'!"));
		}
		else {
			return lib_plankton.sha256.get(
				lib_plankton.json.encode(data),
				secret
			);
		}
	}
	
	
	/**
	 */
	export async function verification_check(
		data : any,
		verification : string
	) : Promise<boolean>
	{
		const secret : (null | string) = _espe.conf.get().general.verification_secret;
		if (secret === null) {
			return Promise.reject<boolean>(new Error("no verification secret specified; add in conf as 'general.verification_secret'!"));
		}
		else {
			const verification_expected : string = lib_plankton.sha256.get(
				lib_plankton.json.encode(data),
				secret
			);
			return (verification === verification_expected);
		}
	}
	
	
	/**
	 * @todo outsource?
	 */
	async function email_send_real(
		smtp_credentials : {
			host : string;
			port : int;
			username : string;
			password : string;
		},
		receivers : Array<string>,
		subject : string,
		content : string,
		options : {
			sender ?: (null | string);
		} = {}
	) : Promise<void>
	{
		options = Object.assign(
			{
				"sender": /*null*/"admin@example.org",
			},
			options
		);
		lib_plankton.log.info(
			"email_send_real",
			{
				"receivers": receivers,
				"subject": subject,
			}
		);
		const nm_nodemailer = require("nodemailer");
		const transporter = nm_nodemailer.createTransport(
			{
				"host": smtp_credentials.host,
				"port": smtp_credentials.port,
				"secure": false,
				"auth": {
					"user": smtp_credentials.username,
					"pass": smtp_credentials.password,
				},
				"debug": true,
			}
		);
		const info = await transporter.sendMail(
			{
				"from": (options.sender ?? ""),
				"to": receivers.join(", "),
				"subject": subject,
				"text": content,
			}
		)
	}
	
	
	/**
	 */
	export async function email_send(
		receivers : Array<string>,
		subject : string,
		content : string
	) : Promise<void>
	{
		const mode : string = _espe.conf.get().email_sending.kind;
		lib_plankton.log.info(
			"email_send",
			{
				"mode": mode,
				"receivers": receivers,
				"subject": subject,
			}
		);
		switch (mode) {
			case "regular": {
				type type_parameters = {
					smtp_credentials : type_smtp_credentials;
					sender : string;
				};
				const parameters : type_parameters = (_espe.conf.get().email_sending.data as type_parameters);
				if (parameters.smtp_credentials === null) {
					return Promise.reject<void>("no smtp credentials specified; add in conf as 'email_sending.data.smtp_credentials'!");
				}
				else {
					return email_send_real(
						parameters.smtp_credentials,
						receivers,
						subject,
						content,
						{
							"sender": parameters.sender,
						}
					);
				}
				break;
			}
			case "redirect": {
				type type_parameters = {
					smtp_credentials : type_smtp_credentials;
					sender : string;
					target : string;
				};
				const parameters : type_parameters = (_espe.conf.get().email_sending.data as type_parameters);
				if (parameters.smtp_credentials === null) {
					return Promise.reject<void>("no smtp credentials specified; add in conf as 'email_sending.data.smtp_credentials'!");
				}
				else {
					return email_send_real(
						parameters.smtp_credentials,
						[parameters.target],
						lib_plankton.string.coin(
							"[REDIRECTION] {{receivers}} | {{original_subject}}",
							{
								"receivers": receivers.join(", "),
								"original_subject": subject
							}
						),
						content,
						{
							"sender": parameters.sender,
						}
					);
				}
				break;
			}
			case "console": {
				lib_plankton.log.info(
					"email_send_content",
					{
						"content": content,
					}
				);
				break;
			}
			case "drop": {
				// do nothing
				break;
			}
			default: {
				throw (new Error("unhandled email mode: " + mode));
				break;
			}
		}
	}
	
	
	/**
	 */
	export function frontend_url_check(
	) : void
	{
		const frontend_url_base : (null | string) = _espe.conf.get().settings.frontend_url_base;
		if (frontend_url_base === null) {
			throw (new Error("no frontend url base set; add in conf as 'settings.frontend_url_base'!"));
		}
		else {
			// do nothing
		}
	}
	
	
	/**
	 */
	export function frontend_url_get(
		template : string,
		arguments_ : Record<string, string>
	) : (null | string)
	{
		const frontend_url_base : (null | string) = _espe.conf.get().settings.frontend_url_base;
		if (frontend_url_base === null) {
			// throw (new Error("no frontend url base set; add in conf as 'settings.frontend_url_base'!"));
			return null;
		}
		else {
			return lib_plankton.string.coin(
				"{{base}}/{{rest}}",
				{
					"base": frontend_url_base,
					"rest": lib_plankton.string.coin(template, arguments_),
				}
			);
		}
	}
	
	
	/**
	 */
	export async function notify_admins(
		subject : string,
		body : string
	) : Promise<void>
	{
		await _espe.helpers.email_send(
			(
				(
					_espe.conf.get().admins
					.map(admin => admin.email_address)
					.filter(x => (x !== null))
				) as Array<string>
			),
			subject,
			body
		);
	}
	
}
