<script setup lang="ts">
	import type { ID, Line, Marker } from "facilmap-types";
	import { combineZoomDestinations, flyTo, getZoomDestinationForLine, getZoomDestinationForMarker } from "../../utils/zoom";
	import Icon from "../ui/icon.vue";
	import MarkerInfo from "../marker-info/marker-info.vue";
	import LineInfo from "../line-info/line-info.vue";
	import { computed, ref, watch } from "vue";
	import { useToasts } from "../ui/toasts/toasts.vue";
	import { showConfirm } from "../ui/alert.vue";
	import { useCarousel } from "../../utils/carousel";
	import ZoomToObjectButton from "../ui/zoom-to-object-button.vue";
	import { injectContextRequired, requireClientContext, requireMapContext } from "../facil-map-context-provider/facil-map-context-provider.vue";
	import vTooltip from "../../utils/tooltip";
	import { formatTypeName, isLine, isMarker, normalizeLineName, normalizeMarkerName } from "facilmap-utils";
	import { useI18n } from "../../utils/i18n";

	const context = injectContextRequired();
	const client = requireClientContext(context);
	const mapContext = requireMapContext(context);
	const toasts = useToasts();
	const i18n = useI18n();

	const props = defineProps<{
		objects: Array<Marker | Line>;
	}>();

	const emit = defineEmits<{
		"click-object": [object: Marker | Line, event: MouseEvent];
	}>();

	const isDeleting = ref(false);
	const openedObjectId = ref<ID>();
	const openedObjectType = ref<"marker" | "line">();

	const carouselRef = ref<HTMLElement>();
	const carousel = useCarousel(carouselRef);

	function zoomToObject(object: Marker | Line): void {
		const zoomDestination = isMarker(object) ? getZoomDestinationForMarker(object) : isLine(object) ? getZoomDestinationForLine(object) : undefined;
		if (zoomDestination)
			flyTo(mapContext.value.components.map, zoomDestination);
	}

	function openObject(object: Marker | Line): void {
		openedObjectId.value = object.id;
		openedObjectType.value = isMarker(object) ? "marker" : isLine(object) ? "line" : undefined;
		carousel.setTab(1);
	}

	const openedObject = computed(() => {
		let openedObject: Marker | Line | undefined = undefined;
		if (openedObjectId.value != null) {
			if (openedObjectType.value == "marker")
				openedObject = client.value.markers[openedObjectId.value];
			else if (openedObjectType.value == "line")
				openedObject = client.value.lines[openedObjectId.value];
		}

		return openedObject && props.objects.includes(openedObject) ? openedObject : undefined;
	});

	watch(openedObject, () => {
		if (!openedObject.value)
			carousel.setTab(0);
	});

	async function deleteObjects(): Promise<void> {
		toasts.hideToast(`fm${context.id}-multiple-info-delete`);

		if (!props.objects || !await showConfirm({
			title: i18n.t("multiple-info.delete-objects-title", { count: props.objects.length }),
			message: i18n.t("multiple-info.delete-objects-message", { count: props.objects.length }),
			variant: "danger",
			okLabel: i18n.t("multiple-info.delete-objects-ok")
		}))
			return;

		isDeleting.value = true;

		try {
			for (const object of props.objects) {
				if (isMarker(object))
					await client.value.deleteMarker({ id: object.id });
				else if (isLine(object))
					await client.value.deleteLine({ id: object.id });
			}
		} catch (err) {
			toasts.showErrorToast(`fm${context.id}-multiple-info-delete`, () => i18n.t("multiple-info.delete-objects-error"), err);
		} finally {
			isDeleting.value = false;
		}
	}

	const zoomDestination = computed(() => {
		return combineZoomDestinations(props.objects.map((object) => {
			if (isMarker(object))
				return getZoomDestinationForMarker(object);
			else if (isLine(object))
				return getZoomDestinationForLine(object);
			else
				return undefined;
		}));
	});
</script>

<template>
	<div class="fm-multiple-info">
		<div class="carousel slide fm-flex-carousel" ref="carouselRef">
			<div class="carousel-item" :class="{ active: carousel.tab === 0 }">
				<ul class="list-group fm-search-box-collapse-point">
					<li v-for="object in props.objects" :key="`${isMarker(object) ? 'm' : 'l'}-${object.id}`" class="list-group-item active">
						<span class="text-break">
							<a href="javascript:" @click="emit('click-object', object, $event)">{{isMarker(object) ? normalizeMarkerName(object.name) : normalizeLineName(object.name)}}</a>
							{{" "}}
							<span class="result-type" v-if="client.types[object.typeId]">({{formatTypeName(client.types[object.typeId].name)}})</span>
						</span>
						<a href="javascript:" @click="zoomToObject(object)" v-tooltip.left="i18n.t('multiple-info.zoom-to-object')"><Icon icon="zoom-in" :alt="i18n.t('multiple-info.zoom')"></Icon></a>
						<a href="javascript:" @click="openObject(object)" v-tooltip.right="i18n.t('multiple-info.show-details')"><Icon icon="arrow-right" :alt="i18n.t('multiple-info.details')"></Icon></a>
					</li>
				</ul>

				<div class="btn-toolbar mt-2">
					<ZoomToObjectButton
						v-if="zoomDestination"
						:label="i18n.t('multiple-info.zoom-to-object-label')"
						size="sm"
						:destination="zoomDestination"
					></ZoomToObjectButton>

					<button
						v-if="!client.readonly"
						type="button"
						class="btn btn-secondary btn-sm"
						@click="deleteObjects()"
						:disabled="isDeleting || mapContext.interaction"
					>
						<div v-if="isDeleting" class="spinner-border spinner-border-sm"></div>
						{{i18n.t("multiple-info.delete")}}
					</button>
				</div>
			</div>

			<div class="carousel-item" :class="{ active: carousel.tab === 1 }">
				<MarkerInfo
					v-if="openedObject && isMarker(openedObject)"
					:markerId="openedObject.id"
					show-back-button
					@back="carousel.setTab(0)"
				></MarkerInfo>
				<LineInfo
					v-else-if="openedObject && isLine(openedObject)"
					:lineId="openedObject.id"
					show-back-button
					@back="carousel.setTab(0)"
				></LineInfo>
			</div>
		</div>
	</div>
</template>

<style lang="scss">
	.fm-multiple-info {
		display: flex;
		flex-direction: column;
		min-height: 0;

		.list-group-item {
			display: flex;
			align-items: center;

			> :first-child {
				flex-grow: 1;
			}
		}
	}
</style>