
namespace _zeitbild.repository.calendar
{
	
	/**
	 */
	type type_dispersal = {
		core_row : Record<
			string,
			any
		>;
		member_rows : Array<
			Record<
				string,
				any
			>
		>;
	};
	
	
	/**
	 */
	var _core_store : (
		null
		|
		lib_plankton.storage.type_store<
			_zeitbild.type.calendar_id,
			Record<string, any>,
			{},
			lib_plankton.storage.type_sql_table_autokey_search_term,
			Record<string, any>
		>
	) = null;
	
	
	/**
	 */
	var _member_chest : (
		null
		|
		lib_plankton.storage.type_chest<
			Array<any>,
			Record<string, any>,
			lib_plankton.database.type_description_create_table,
			lib_plankton.storage.sql_table_common.type_sql_table_common_search_term,
			Record<string, any>
		>
	) = null;
	
	
	/**
	 */
	function get_core_store(
	) : lib_plankton.storage.type_store<
		_zeitbild.type.calendar_id,
		Record<string, any>,
		{},
		lib_plankton.storage.type_sql_table_autokey_search_term,
		Record<string, any>
	>
	{
		if (_core_store === null) {
			_core_store = lib_plankton.storage.sql_table_autokey_store(
				{
					"database_implementation": _zeitbild.database.get_implementation(),
					"table_name": "calendars",
					"key_name": "id",
				}
			);
		}
		else {
			// do nothing
		}	
		return _core_store;
	}
	
	
	/**
	 */
	function get_member_chest(
	) : lib_plankton.storage.type_chest<
		Array<any>,
		Record<string, any>,
		lib_plankton.database.type_description_create_table,
		lib_plankton.storage.sql_table_common.type_sql_table_common_search_term,
		Record<string, any>
	>
	{
		if (_member_chest === null) {
			_member_chest = lib_plankton.storage.sql_table_common.chest(
				{
					"database_implementation": _zeitbild.database.get_implementation(),
					"table_name": "calendar_members",
					"key_names": ["calendar_id","user_id"],
				}
			);
		}
		else {
			// do nothing
		}	
		return _member_chest;
	}
	
	
	/**
	 */
	function encode(
		object : _zeitbild.type.calendar_object
	) : type_dispersal
	{
		return {
			"core_row": {
				"name": object.name,
				"public": object.public,
				"resource_id": object.resource_id,
			},
			"member_rows": (
				object.members
				.map(
					(member) => ({
						// "calendar_id": calendar_id,
						"user_id": member.user_id,
						"role": member.role,
					})
				)
			),
		};
	}
	
	
	/**
	 */
	function decode(
		dispersal : type_dispersal
	) : _zeitbild.type.calendar_object
	{
		return {
			"name": dispersal.core_row["name"],
			"public": dispersal.core_row["public"],
			"members": (
				dispersal.member_rows
				.map(
					(member_row) => ({
						"calendar_id": member_row["calendar_id"],
						"user_id": member_row["user_id"],
						"role": member_row["role"],
					})
				)
			),
			"resource_id": dispersal.core_row["resource_id"],
		};
	}
	
	
	/**
	 * @todo optimize
	 */
	export async function list(
		search_term : (null | string)
	) : Promise<
		Array<
			{
				id : _zeitbild.type.calendar_id;
				preview : {
					name : string;
				};
			}
		>
	>
	{
		return (
			(
				await get_core_store().search(
					{
						"expression": "(public = TRUE)",
						"arguments": {
						}
					}
				)
			)
			.filter(
				({"key": key, "preview": preview}) => (
					(
						(search_term === null)
						||
						(search_term.length <= 1)
					)
					? true
					: (
						preview["name"].toLowerCase().includes(search_term.toLowerCase())
					)
				)
			)
			.map(
				({"key": key, "preview": preview}) => ({
					"id": key,
					"preview": {
						"name": preview["name"],
					}
				})
			)
		);
	}
	
	
	/**
	 */
	export function read(
		id : _zeitbild.type.calendar_id
	) : Promise<_zeitbild.type.calendar_object>
	{
		return (
			get_core_store().read(id)
			.then(
				(core_row) => (
					get_member_chest().search(
						{
							"expression": "(calendar_id = $calendar_id)",
							"arguments": {
								"calendar_id": id,
							}
						}
					)
					.then(
						(member_rows) => Promise.resolve<type_dispersal>(
							{
								"core_row": core_row,
								"member_rows": member_rows,
							}
						)
					)
					.then(
						(dispersal) => Promise.resolve<_zeitbild.type.calendar_object>(
							decode(dispersal)
						)
					)
				)
			)
		);
	}
	
	
	/**
	 */
	export function create(
		calendar_object : _zeitbild.type.calendar_object
	) : Promise<_zeitbild.type.calendar_id>
	{
		return (
			Promise.resolve<_zeitbild.type.calendar_object>(calendar_object)
			.then<type_dispersal>(
				(calendar_object) => Promise.resolve<type_dispersal>(encode(calendar_object))
			)
			.then<_zeitbild.type.calendar_id>(
				(dispersal) => (
					get_core_store().create(dispersal.core_row)
					.then<_zeitbild.type.calendar_id>(
						(calendar_id) => (
							Promise.all(
								dispersal.member_rows
								.map(
									(member_row) => get_member_chest().write(
										[calendar_id, member_row["user_id"]],
										{"role": member_row["role"]}
									)
								)
							)
							.then(
								() => Promise.resolve<_zeitbild.type.calendar_id>(calendar_id)
							)
						)
					)
				)
			)
		);
	}
	
	
	/**
	 * @todo sort for role, public and id
	 */
	export function overview(
		user_id : _zeitbild.type.user_id
	) : Promise<
		Array<
			{
				id : _zeitbild.type.calendar_id;
				name : string;
				public : boolean;
				role : (null | _zeitbild.type.role);
			}
		>
	>
	{
		return (
			_zeitbild.database.get_implementation().query_free_get(
				{
					"template": "SELECT x.id AS id, x.name AS name, x.public AS public, MAX(y.role) AS role FROM calendars AS x LEFT OUTER JOIN calendar_members AS y ON (x.id = y.calendar_id) WHERE (x.public OR (y.user_id = $user_id)) GROUP BY x.id;",
					"arguments": {
						"user_id": user_id,
					}
				}
			)
			.then(
				(rows) => Promise.resolve(
					rows.map(
						(row) => ({
							"id": row["id"],
							"name": row["name"],
							"public": (row["public"] === 1),
							"role": row["role"],
						})
					)
				)
			)
			/*
			.then(
				(entries) => Promise.resolve(
					entries.toSorted(
						(x, y) => (x
					)
				)
			)
			 */
		)
	}
}

