<script setup lang="ts">
import type { SetupContext } from 'vue'
import type { CalendarEvent } from '../CalendarTypes'
import { formatDate, getI18n, useI18n, Icon, Card } from '@bagelink/vue'
import { ref, computed, watch, watchEffect, nextTick, onMounted, onUnmounted, useSlots } from 'vue'

interface AgendaViewEvent extends CalendarEvent {
	durationMin: number
}

interface DayGroup {
	dateKey: string
	date: Date
	dayNumber: string
	monthShort: string
	weekdayLong: string
	isToday: boolean
	events: AgendaViewEvent[]
}

const props = defineProps<{
	events: CalendarEvent[]
	startDate: Date
}>()

const emit = defineEmits<{
	(e: 'eventClick', event: CalendarEvent): void
	(e: 'dateChange', date: Date): void
	(e: 'openPopover', event: CalendarEvent, position?: { top: number, left: number }): void
}>()

const slots: SetupContext['slots'] = useSlots()
const { t } = useI18n()

const containerRef = ref<HTMLElement | null>(null)

function getLocale(): string {
	try { return (getI18n().global.locale as { value: string }).value } catch { return 'en' }
}

function formatDuration(minutes: number): string {
	if (minutes < 60) return `${minutes} min`
	const h = Math.floor(minutes / 60)
	const m = minutes % 60
	return m ? `${h}h ${m}m` : `${h}h`
}

// Group events by day
const dayGroups = computed((): DayGroup[] => {
	const locale = getLocale()
	const today = new Date().toDateString()

	const sorted = [...props.events].sort(
		(a, b) => new Date(a.start_time).getTime() - new Date(b.start_time).getTime()
	)

	const map = new Map<string, DayGroup>()

	for (const event of sorted) {
		const date = new Date(event.start_time)
		const dateKey = date.toDateString()

		if (!map.has(dateKey)) {
			map.set(dateKey, {
				dateKey,
				date,
				dayNumber: date.toLocaleDateString(locale, { day: '2-digit' }),
				monthShort: date.toLocaleDateString(locale, { month: 'short' }),
				weekdayLong: date.toLocaleDateString(locale, { weekday: 'long' }),
				isToday: dateKey === today,
				events: [],
			})
		}

		const durationMin = Math.round(
			(new Date(event.end_time).getTime() - new Date(event.start_time).getTime()) / 60000
		)
		map.get(dateKey)!.events.push({ ...event, durationMin })
	}

	return Array.from(map.values())
})

const scrolledOnce = ref(false)

// Scroll tracking (informs parent of visible date for header display only)
function handleScroll() {
	if (!containerRef.value) { return }
	const container = containerRef.value
	const dayEls = container.querySelectorAll<HTMLElement>('.agenda-day-group')
	const containerTop = container.getBoundingClientRect().top

	let closest: HTMLElement | null = null
	let minDist = Infinity

	dayEls.forEach((el) => {
		const dist = Math.abs(el.getBoundingClientRect().top - containerTop)
		if (dist < minDist) { minDist = dist; closest = el }
	})

	if (closest) {
		const dateStr = (closest as HTMLElement).dataset.date
		if (dateStr) { emit('dateChange', new Date(dateStr)) }
	}
}

function handleEventSelection(event: CalendarEvent, domEvent?: MouseEvent) {
	if (!slots.eventContent) {
		emit('eventClick', event)
		return
	}
	if (domEvent) {
		const rect = (domEvent.currentTarget as HTMLElement).getBoundingClientRect()
		emit('openPopover', event, {
			top: rect.top + window.scrollY + rect.height / 2,
			left: rect.left + window.scrollX + rect.width + 10,
		})
	} else {
		emit('openPopover', event)
	}
}

function toMidnight(date: Date): number {
	const d = new Date(date)
	d.setHours(0, 0, 0, 0)
	return d.getTime()
}

function scrollToDate(targetDate: Date, behavior: 'smooth' | 'instant' | 'auto' = 'instant', direction: 'forward' | 'backward' | 'nearest' = 'nearest') {
	if (!containerRef.value) { return }
	const dayEls = Array.from(containerRef.value.querySelectorAll<HTMLElement>('.agenda-day-group'))
	if (!dayEls.length) { return }
	// Normalize to midnight to avoid timestamp-within-day comparison issues
	const targetDay = toMidnight(targetDate)
	let closest: HTMLElement | null = null
	let minDiff = Infinity

	if (direction === 'forward') {
		// First day on or after target date (midnight-normalized)
		for (const el of dayEls) {
			const dateStr = el.dataset.date
			if (!dateStr) { continue }
			const t = toMidnight(new Date(dateStr))
			if (t >= targetDay && t - targetDay < minDiff) { minDiff = t - targetDay; closest = el }
		}
	} else if (direction === 'backward') {
		// Last day on or before target date (midnight-normalized)
		for (const el of dayEls) {
			const dateStr = el.dataset.date
			if (!dateStr) { continue }
			const t = toMidnight(new Date(dateStr))
			if (t <= targetDay && targetDay - t < minDiff) { minDiff = targetDay - t; closest = el }
		}
	}

	// Fallback to nearest (also used for 'nearest' direction)
	if (!closest) {
		for (const el of dayEls) {
			const dateStr = el.dataset.date
			if (!dateStr) { continue }
			const diff = Math.abs(toMidnight(new Date(dateStr)) - targetDay)
			if (diff < minDiff) { minDiff = diff; closest = el }
		}
	}

	closest?.scrollIntoView({ block: 'start', behavior })
}

// Navigate to date when buttons are clicked (parent changes startDate)
watch(() => props.startDate, (newDate, oldDate) => {
	const direction = !oldDate || toMidnight(newDate) >= toMidnight(oldDate) ? 'forward' : 'backward'
	nextTick(() => scrollToDate(newDate, 'smooth', direction))
})

// Initial scroll to today — wait until data covers today before scrolling,
// to avoid scrolling to a wrong date during partial/incremental data load.
watchEffect(() => {
	if (scrolledOnce.value || !dayGroups.value.length) { return }
	const todayTime = new Date().getTime()
	const hasTodayOrLater = dayGroups.value.some(g => g.date.getTime() >= todayTime - 86400000)
	if (!hasTodayOrLater) { return }
	scrolledOnce.value = true
	nextTick(() => scrollToDate(new Date(), 'instant', 'nearest'))
})

onMounted(() => { containerRef.value?.addEventListener('scroll', handleScroll) })
onUnmounted(() => { containerRef.value?.removeEventListener('scroll', handleScroll) })
</script>

<template>
<div ref="containerRef" class="display-flex column h-100p overflow gap-0">
	<template v-if="dayGroups.length === 0">
		<div class="flex h-100p justify-content-center column gap-1 opacity-3">
			<Icon icon="calendar" size="4" weight="200" />
			{{ t('calendar.agenda.noEvents') }}
		</div>
	</template>

	<section v-for="group in dayGroups" :key="group.dateKey" class="mb-1 agenda-day-group" :data-date="group.date.toISOString()" :data-today="group.isToday || undefined">
		<div class="sticky z-2 flex gap-05 p-1 m_p-05 mb-05" :class="{ 'bg-primary-light': group.isToday, 'bg-bg': !group.isToday }">
			<div class="bg-white border line-height-12 radius-1 grid align-items-center  px-05 py-025 txt-center">
				<p class="txt18">{{ group.dayNumber }}</p>
				<p class="txt12">{{ group.monthShort }}</p>
			</div>
			<div>
				<p class=" line-height-12">{{ group.weekdayLong }}</p>
				<p class="txt12 opacity-6">
					{{ t('calendar.agenda.eventsCount', group.events.length, { named: { n: group.events.length } }) }}
				</p>
			</div>
			<p v-if="group.isToday" class="ms-auto">{{ t('calendar.today') }}</p>
		</div>

		<!-- Event rows -->
		<article v-for="event in group.events" :key="event.id" class="agenda-event-row grid gap-05 hover pe-1" @click.stop="handleEventSelection(event, $event)">
			<div class="agenda-event-time txt-center pt-1 txt14 opacity-6 bold relative">
				{{ formatDate(event.start_time, { format: 'HH:mm' }) }}
			</div>
			<Card class="agenda-event-card overflow-hidden transition py-025 px-075 my-025" frame :style="{ '--event-color': event.color || 'var(--bgl-primary)' }">
				<div class="flex space-between">
					<h3 class="txt16 m-0 semi">{{ event.title }}</h3>
					<p class="txt12 opacity-6">{{ formatDuration(event.durationMin) }}</p>
				</div>
				<p v-if="event.description" class="txt12 opacity-6">{{ event.description }}</p>
			</Card>
		</article>
	</section>
</div>
</template>

<style scoped>

.agenda-event-row {
grid-template-columns: 72px 1fr;
align-items: stretch;
}

.agenda-event-time::after {
content: '';
display: block;
width: 1px;
height: calc(100% - 2rem);
background: var(--bgl-border-color, #e6e8ec);
margin: 0.5rem auto 0;
}

/* .agenda-event-card {
border-inline-start: var(--event-color, var(--bgl-primary)) solid calc(var(--bgl-card-border-radius) + 0.25rem); 
} */

.agenda-event-card h3::before {
content: '';
width: 10px;
height: 10px;
display: inline-block;
border-radius: 100%;
margin-inline-end: 0.35rem;
background: var(--event-color, var(--bgl-primary, #2563eb));
}

@media (max-width: 910px) {
.agenda-event-row {
grid-template-columns: 50px 1fr;
}
}

</style>
