/*
This file is part of »dali«.

Copyright 2025 'kcf' <fenris@folksprak.org>

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

»dali« 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 Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »dali«. If not, see <http://www.gnu.org/licenses/>.
 */


/**
 */
namespace _dali.helpers
{
	
	/**
	 * @todo outsource
	 */
	function is_touch_device(
	)
	: boolean
	{
		return (
			("ontouchstart" in window)
			||
			(navigator.maxTouchPoints > 0)
			||
			(navigator["msMaxTouchPoints"] > 0)
		);
	}
	
	
	/**
	 */
	var _template_cache : Record<string, string> = {};

	
	/**
	 */
	export function view_mode_determine(
		mode_descriptor : string
	)
	: _dali.enum_view_mode
	{
		if (mode_descriptor === "auto")
		{
			return (
				(window.innerWidth >= 1000)
				?
				_dali.enum_view_mode.week
				:
				_dali.enum_view_mode.list
			);
		}
		else
		{
			return view_mode_decode(mode_descriptor);
		}
	}
	
	
	/**
	 */
	export function view_kind_determine(
		mode_descriptor : string
	)
	: _dali.enum_view_kind
	{
		if (mode_descriptor === "auto")
		{
			return (
				is_touch_device()
				?
				_dali.enum_view_kind.touch
				:
				_dali.enum_view_kind.regular
			);
		}
		else
		{
			return view_kind_decode(mode_descriptor);
		}
	}
	
	
	/**
	 */
	export async function template_coin(
		group : string,
		name : string,
		data : Record<string, string>
	) : Promise<string>
	{
		let content : string;
		const key : string = lib_plankton.string.coin(
			"{{group}}/{{name}}",
			{
				"group": group,
				"name": name,
			}
		);
		if (! (key in _template_cache)) {
			content = (
				(
					await lib_plankton.file.read(
						lib_plankton.string.coin(
							"templates/{{group}}/{{name}}.html.tpl",
							{
								"group": group,
								"name": name,
							}
						)
					)
				)
				.toString()
			);
			_template_cache[key] = content;
		}
		else {
			content = _template_cache[key];
		}
		return Promise.resolve<string>(
			lib_plankton.string.coin(
				content,
				data
			)
		);
	}
	
	
	/**
	 */
	export async function element_from_template(
		group : string,
		name : string,
		data : Record<string, string>
	)
	: Promise<HTMLElement>
	{
		const dom_dummy = document.createElement("div");
		dom_dummy.innerHTML = await _dali.helpers.template_coin(
			group,
			name,
			data
		);
		return (dom_dummy.children[0] as HTMLElement);
	}
	
	
	/**
	 * @todo outsource
	 */
	export async function promise_row<type_result>(
		members : Array<
			() => Promise<type_result>
		>
	)
	: Promise<
		Array<
			type_result
		>
	>
	{
		let results : Array<type_result> = [];
		for await (const member of members) {
			results.push(await member());
		}
		return Promise.resolve<Array<type_result>>(results);
	}
	
	
	/**
	 */
	export function input_access_level(
	)
	: lib_plankton.zoo_input.interface_input<_dali.enum_access_level>
	{
		return (
			new lib_plankton.zoo_input.class_input_wrapped<
				/*("none" | "view" | "edit" | "admin")*/string,
				_dali.enum_access_level
			>(
				new lib_plankton.zoo_input.class_input_selection(
					[
						{
							"value": "none",
							"label": lib_plankton.translate.get("access_level.none"),
						},
						{
							"value": "view",
							"label": lib_plankton.translate.get("access_level.view")
						},
						{
							"value": "edit",
							"label": lib_plankton.translate.get("access_level.edit")
						},
						{
							"value": "admin",
							"label": lib_plankton.translate.get("access_level.admin")
						},
					]
				),
				(raw) => {
					switch (raw) {
						case "none": return _dali.enum_access_level.none;
						case "view": return _dali.enum_access_level.view;
						case "edit": return _dali.enum_access_level.edit;
						case "admin": return _dali.enum_access_level.admin;
					}
				},
				(access_level) => {
					switch (access_level) {
						case _dali.enum_access_level.none: return "none";
						case _dali.enum_access_level.view: return "view";
						case _dali.enum_access_level.edit: return "edit";
						case _dali.enum_access_level.admin: return "admin";
					}
				},
			)
		);
	}
	
	
	/**
	 */
	export function input_attributed_access_group(
		groups : Array<{id : _dali.type_group_id; object : _dali.type_group_object;}>
	)
	: lib_plankton.zoo_input.class_input_hashmap<
		_dali.type_group_id,
		_dali.enum_access_level
	>
	{
		return (
			new lib_plankton.zoo_input.class_input_hashmap<_dali.type_group_id, _dali.enum_access_level>(
				// hash_key
				(group_id) => group_id.toFixed(0),
				// key_input_factory
				() => new lib_plankton.zoo_input.class_input_wrapped<string, int>(
					new lib_plankton.zoo_input.class_input_selection(
						groups
						.map(
							(group) => ({
								"value": group.id.toFixed(0),
								"label": group.object.label,
							})
						)
					),
					x => parseInt(x),
					x => x.toFixed(0)
				),
				// value_input_factory
				() => input_access_level()
			)
		);
	}
	
	
	/**
	 */
	export function input_attributed_access_user(
		users : Array<{id : _dali.type_user_id; name : string;}>
	)
	: lib_plankton.zoo_input.class_input_hashmap<
		_dali.type_user_id,
		_dali.enum_access_level
	>
	{
		return (
			new lib_plankton.zoo_input.class_input_hashmap<_dali.type_user_id, _dali.enum_access_level>(
				// hash_key
				(user_id) => user_id.toFixed(0),
				// key_input_factory
				() => new lib_plankton.zoo_input.class_input_wrapped<string, int>(
					new lib_plankton.zoo_input.class_input_selection(
						users
						.map(
							(user) => ({
								"value": user.id.toFixed(0),
								"label": user.name,
							})
						)
					),
					x => parseInt(x),
					x => x.toFixed(0)
				),
				// value_input_factory
				() => input_access_level()
			)
		);
	}
	
	
	/**
	 */
	export function datetime_input(
		use_fallback : boolean
	)
	: lib_plankton.zoo_input.interface_input<lib_plankton.pit.type_datetime>
	{
		return (
			use_fallback
			?
			new lib_plankton.zoo_input.class_input_wrapped<
				{
					date : string;
					time : string;
				},
				(
					null
					|
					lib_plankton.pit.type_datetime
				)
			>(
				new lib_plankton.zoo_input.class_input_group(
					[
						{
							"name": "date",
							"input": new lib_plankton.zoo_input.class_input_text(
								{
									"pattern": "[0-9]{4}-[0-9]{2}-[0-9]{2}",
									"placeholder": "YYYY-MM-DD",
								}
							),
							"label": lib_plankton.translate.get("common.date"),
						},
						{
							"name": "time",
							"input": new lib_plankton.zoo_input.class_input_text(
								{
									"pattern": "[0-9]{2}:[0-9]{2}",
									"placeholder": "HH:MM",
								}
							),
							"label": lib_plankton.translate.get("common.time"),
						},
					]
				),
				(inner) => {
					if (inner === null)
					{
						return null;
					}
					else
					{
						const date_parts : Array<string> = ((inner.date === "") ? null : inner.date.split("-"));
						const time_parts : (null | Array<string>) = ((inner.time === "") ? null : inner.time.split(":"));
						const datetime_raw : (null | lib_plankton.pit.type_datetime) = (
							(date_parts === null)
							?
							null
							:
							{
								"timezone_shift": 0,
								"date": {
									"year": parseInt(date_parts[0]),
									"month": parseInt(date_parts[1]),
									"day": parseInt(date_parts[2]),
								},
								"time": (
									(time_parts === null)
									?
									null
									:
									{
										"hour": parseInt(time_parts[0]),
										"minute": parseInt(time_parts[1]),
										"second": 0,
									}
								),
							}
						);
						return (
							(datetime_raw === null)
							?
							null
							:
							{
								"timezone_shift": (
									_dali.conf.get().misc.use_central_europe_specific_datetime_inputs
									?
									lib_plankton.pit.timezone_shift_ce(lib_plankton.pit.from_datetime(datetime_raw))
									:
									0
								),
								"date": datetime_raw.date,
								"time": datetime_raw.time,
							}
						);
					}
				},
				(outer) => {
					if (outer === null)
					{
						return {
							"date": "",
							"time": "",
						};
					}
					else
					{
						return {
							"date": lib_plankton.string.coin(
								"{{year}}-{{month}}-{{day}}",
								{
									"year": outer.date.year.toFixed(0).padStart(4, "0"),
									"month": outer.date.month.toFixed(0).padStart(2, "0"),
									"day": outer.date.day.toFixed(0).padStart(2, "0"),
								}
							),
							"time": (
								(outer.time === null)
								?
								""
								:
								lib_plankton.string.coin(
									"{{hour}}:{{minute}}",
									{
										"hour": outer.time.hour.toFixed(0).padStart(2, "0"),
										"minute": outer.time.minute.toFixed(0).padStart(2, "0"),
									}
								)
							),
						};
					}
				}
			)
			:
			(
				_dali.conf.get().misc.use_central_europe_specific_datetime_inputs
				?
				new lib_plankton.zoo_input.class_input_datetime_central_europe(
					{
						"label_date": lib_plankton.translate.get("common.date"),
						"label_time": lib_plankton.translate.get("common.time"),
					}
				)
				:
				new lib_plankton.zoo_input.class_input_datetime(
					{
						"label_timezone_shift": lib_plankton.translate.get("common.timezone_shift"),
						"label_date": lib_plankton.translate.get("common.date"),
						"label_time": lib_plankton.translate.get("common.time"),
					}
				)
			)
		);
	}
	
	
	/**
	 */
	export function event_color(
		hue : float
	)
	:
	string
	{
		return lib_plankton.color.output_hex(
			lib_plankton.color.make_hsv(
				{
					"hue": hue,
					"saturation": 0.375,
					"value": 0.375,
				}
			),
		);
	}
	
	
	/**
	 */
	export function month_name(
		month : int
	)
	: string
	{
		const keys : Array<string> = [
			"common.monthname.january",
			"common.monthname.february",
			"common.monthname.march",
			"common.monthname.april",
			"common.monthname.may",
			"common.monthname.june",
			"common.monthname.july",
			"common.monthname.august",
			"common.monthname.september",
			"common.monthname.october",
			"common.monthname.november",
			"common.monthname.december",
		];
		return lib_plankton.translate.get(keys[month-1]);
	}
	
	
	/**
	 */
	export function loading(
		mode : boolean
	)
	: void
	{
		if (! mode)
		{
			_dali.overlay.toggle({"mode": false});
		}
		else
		{
			_dali.overlay.get_content_element().innerHTML = ". . .";
			_dali.overlay.toggle({"mode": true});
		}
	}
	
}
