/*
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.service.admin
{
	
	/**
	 */
	export type type_value = {
		id : _espe.type.admin_id;
		object : _espe.type.admin_object;
	};
	
	
	/**
	 */
	export async function add(
		name : string,
		email_address : (null | string),
		password : string
	) : Promise<_espe.type.admin_id>
	{
		const admin_object : _espe.type.admin_object = {
			"name": name,
			"email_address": email_address,
			"password_image": (await _espe.helpers.bcrypt_compute(password)),
			"password_fail_count": 0,
		};
		return _espe.repository.admin.create(admin_object);
	}
	
	
	/**
	 */
	async function get(
		name : string
	) : Promise<(null | type_value)>
	{
		const hits : Array<
			{
				id : _espe.type.admin_id;
				preview : _espe.type.admin_object;
			}
		> = await _espe.repository.admin.list(name);
		return Promise.resolve<(null | type_value)>(
			(hits.length === 1)
			?
			{"id": hits[0].id, "object": hits[0].preview}
			:
			null
		);
	}
	
	
	/**
	 */
	async function check_password(
		value : type_value,
		password_given : string
	) : Promise<boolean>
	{
		return _espe.helpers.bcrypt_compare(value.object.password_image, password_given);
	}
	
	
	/**
	 */
	export async function login(
		name : string,
		password : string
	) : Promise<(null | type_value)>
	{
		const value : (null | type_value) = await get(name);
		if (value === null) {
			return null;
		}
		else {
			/**
			 * @todo outsource fail count threshold?
			 */
			const password_fail_threshold : int = 3;
			if (value.object.password_fail_count >= password_fail_threshold) {
				lib_plankton.log.notice(
					"admin_password_fail_threshold_exceeded",
					{
						"id": value.id,
						"name": value.object.name,
						"password_fail_count": (value.object.password_fail_count + 1)
					}
				);
				await _espe.repository.admin.update(
					value.id,
					{
						"name": value.object.name,
						"email_address": value.object.email_address,
						"password_image": value.object.password_image,
						"password_fail_count": (value.object.password_fail_count + 1),
					}
				);
				return null;
			}
			else {
				if (! (await check_password(value, password))) {
					await _espe.repository.admin.update(
						value.id,
						{
							"name": value.object.name,
							"email_address": value.object.email_address,
							"password_image": value.object.password_image,
							"password_fail_count": (value.object.password_fail_count + 1),
						}
					);
					return null;
				}
				else {
					return value;
				}
			}
		}
	}
	
	/**
	 */
	export async function email_addresses(
	) : Promise<Array<string>>
	{
		return (
			(
				(await _espe.repository.admin.list(null))
				.map(hit => hit.preview["email_address"])
				.filter(x => (x !== null))
			) as Array<string>
		);
	}
	
	
	/**
	 */
	export async function notify_all(
		subject : string,
		body : string
	) : Promise<void>
	{	
		return _espe.helpers.email_send(
			await email_addresses(),
			subject,
			body
		);
	}
	
}
