
namespace _zeitbild.service.calendar
{
	
	/**
	 */
	export function add(
		calendar_object : _zeitbild.type.calendar_object
	) : Promise<_zeitbild.type.calendar_id>
	{
		return _zeitbild.repository.calendar.create(calendar_object);
	}
	
	
	/**
	 */
	export async function list(
		search_term : (null | string)
	) : Promise<
		 Array<
			{
				id : _zeitbild.type.calendar_id;
				preview : {
					name : string;
				}
			}
		>
	>
	{
		return (
			_zeitbild.repository.calendar.list(search_term)
			.then(
				x => x.map(
					(y : any) => ({
						"id": y.key,
						"preview": y.preview,
					})
				)
			)
		);
	}
	
	
	/**
	 */
	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.repository.calendar.overview(user_id);
	}
	
	
	/**
	 */
	export async function get(
		calendar_id : _zeitbild.type.calendar_id
	) : Promise<_zeitbild.type.calendar_object>
	{
		return _zeitbild.repository.calendar.read(calendar_id);
	}
	
	
	/**
	 */
	async function get_events(
		calendar_id : _zeitbild.type.calendar_id,
		from_pit : _zeitbild.helpers.type_pit,
		to_pit : _zeitbild.helpers.type_pit
	) : Promise<
		Array<
			_zeitbild.type.event_object
		>
	>
	{
		const calendar_object : _zeitbild.type.calendar_object = await _zeitbild.repository.calendar.read(calendar_id);
		const resource_object : _zeitbild.type.resource_object = await _zeitbild.repository.resource.read(calendar_object.resource_id);
		switch (resource_object.kind) {
			case "local": {
				return Promise.resolve(
					resource_object.data.events
					.filter(
						(event : _zeitbild.type.event_object) => _zeitbild.helpers.pit_is_between(
							_zeitbild.helpers.pit_from_datetime(event.begin),
							from_pit,
							to_pit
						)
					)
				)
				break;
			}
			case "caldav": {
				// TODO readonly
				const url : lib_plankton.url.type_url = lib_plankton.url.decode(
					resource_object.data.url
				);
				const http_request : lib_plankton.http.type_request = {
					"version": "HTTP/2",
					"scheme": ((url.scheme === "https") ? "https" : "http"),
					"host": url.host,
					"path": (url.path ?? "/"),
					"query": url.query,
					"method": lib_plankton.http.enum_method.get,
					"headers": {},
					"body": null,
				};
				// TODO: cache?
				const http_response : lib_plankton.http.type_response = await lib_plankton.http.call(
					http_request,
					{
					}
				);
				const vcalendar : lib_plankton.ical.type_vcalendar = lib_plankton.ical.ics_decode(
					http_response.body.toString(),
					{
					}
				);
				return Promise.resolve(
					vcalendar.vevents
					.map(
						(vevent : lib_plankton.ical.type_vevent) => (
							(vevent.dtstart !== undefined)
							?
							{
								"name": (
									(vevent.summary !== undefined)
									?
									vevent.summary
									:
									"???"
								),
								"begin": _zeitbild.helpers.ical_dt_to_own_datetime(vevent.dtstart),
								"end": (
									(vevent.dtend !== undefined)
									?
									_zeitbild.helpers.ical_dt_to_own_datetime(vevent.dtend)
									:
									null
								),
								"location": (
									(vevent.location !== undefined)
									?
									vevent.location
									:
									null
								),
								"description": (
									(vevent.description !== undefined)
									?
									vevent.description
									:
									null
								),
							}
							:
							null
						)
					)
					.filter(
						(event) => (event !== null)
					)
					.filter(
						(event) => _zeitbild.helpers.pit_is_between(
							_zeitbild.helpers.pit_from_datetime(event.begin),
							from_pit,
							to_pit
						)
					)
				);
				break;
			}
			default: {
				return Promise.reject(
					new Error("invalid resource kind: " + resource_object["kind"])
				);
				break;
			}
		}
	}
	
	
	/**
	 */
	export async function gather_events(
		calendar_ids : Array<_zeitbild.type.calendar_id>,
		from_pit : _zeitbild.helpers.type_pit,
		to_pit : _zeitbild.helpers.type_pit
	) : Promise<
		Array<
			{
				calendar_id : _zeitbild.type.calendar_id;
				calendar_name : string;
				event : _zeitbild.type.event_object;
			}
		>
	>
	{
		return (
			Promise.all(
				calendar_ids
				.map(
					async (calendar_id) => {
						const calendar_object : _zeitbild.type.calendar_object = await _zeitbild.repository.calendar.read(
							calendar_id
						);
						const events : Array<_zeitbild.type.event_object> = await get_events(
							calendar_id,
							from_pit,
							to_pit
						);
						return Promise.resolve(
							events
							.map(
								(event) => ({
									"calendar_id": calendar_id,
									"calendar_name": calendar_object.name,
									"event": event,
								})
							)
						);
					}
				)
			)
			.then(
				(sub_results) => sub_results.reduce(
					(x, y) => x.concat(y),
					[]
				)
			)
		);
	}

}
