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

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

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

const slots: SetupContext['slots'] = useSlots()

// Configuration constants
const slotHeight = 60
const slotDuration = 60
const timeRange = { start: 0, end: 24 }

// Drag state
const dragState = ref({
	isDragging: false,
	start: null as { x: number, y: number } | null,
	end: null as { x: number, y: number } | null,
	startTime: null as Date | null,
	endTime: null as Date | null
})

// Time indicators
const currentTimeTop = ref(0)
const isToday = ref(false)
const currentTimeInterval = ref(null as any)

// Generate hourly time slots
const timeSlots = computed(() => {
	const slots = []
	for (let hour = timeRange.start; hour < timeRange.end; hour++) {
		for (let minute = 0; minute < 60; minute += slotDuration) {
			slots.push({
				hour,
				minute,
				time: `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`
			})
		}
	}
	return slots
})

// Process events for the current day
const processedEvents = computed(() => {
	return props.events
		.filter((event) => {
			const eventDate = new Date(event.start_time)
			return eventDate.toDateString() === props.startDate.toDateString()
		})
		.map((event) => {
			const startDate = new Date(event.start_time)
			const endDate = new Date(event.end_time)

			const startMinutes = startDate.getHours() * 60 + startDate.getMinutes()
			const endMinutes = endDate.getHours() * 60 + endDate.getMinutes()

			const top = (startMinutes / slotDuration) * slotHeight
			const height = Math.max(((endMinutes - startMinutes) / slotDuration) * slotHeight, 30)

			return {
				...event,
				top,
				height
			}
		})
})

// Updates the current time indicator
function updateCurrentTimeIndicator() {
	const now = new Date()

	// Check if today is the selected day
	isToday.value = now.toDateString() === props.startDate.toDateString()

	// Calculate the position for the current time line - use same formula as events
	const minutes = now.getHours() * 60 + now.getMinutes()
	currentTimeTop.value = (minutes / slotDuration) * slotHeight
}

// Event handlers for drag-to-create functionality
function handleMouseDown(e: MouseEvent) {
	const target = e.target as HTMLElement
	if (!target.closest('.time-slot')) return

	dragState.value.isDragging = true
	dragState.value.start = { x: e.clientX, y: e.clientY }
	dragState.value.startTime = getTimeFromPosition(e.clientY)

	document.addEventListener('mousemove', handleMouseMove)
	document.addEventListener('mouseup', handleMouseUp)
}

function handleMouseMove(e: MouseEvent) {
	if (!dragState.value.isDragging) return

	dragState.value.end = { x: e.clientX, y: e.clientY }
	dragState.value.endTime = getTimeFromPosition(e.clientY)
}

function handleMouseUp() {
	if (!dragState.value.isDragging || !dragState.value.startTime || !dragState.value.endTime) return

	let start = new Date(dragState.value.startTime)
	let end = new Date(dragState.value.endTime)

	// Ensure end time is after start time
	if (end < start) [start, end] = [end, start]

	emit('eventCreate', { start_time: start, end_time: end })

	// Reset drag state
	dragState.value = {
		isDragging: false,
		start: null,
		end: null,
		startTime: null,
		endTime: null
	}

	document.removeEventListener('mousemove', handleMouseMove)
	document.removeEventListener('mouseup', handleMouseUp)
}

function getTimeFromPosition(y: number): Date {
	const rect = document.querySelector('.time-slots')?.getBoundingClientRect()
	if (!rect) return new Date()

	// Calculate time using the same formula as for events
	const relativeY = y - rect.top
	const minutesPerSlot = slotDuration
	const slotsFromTop = relativeY / slotHeight
	const minutes = Math.floor(slotsFromTop * minutesPerSlot)

	const date = new Date(props.startDate)
	date.setHours(Math.floor(minutes / 60))
	date.setMinutes(minutes % 60)
	date.setSeconds(0)
	date.setMilliseconds(0)

	return date
}

// Update event handling to emit the openPopover event
function handleEventSelection(event: CalendarEvent, domEvent?: MouseEvent) {
	if (!slots.eventContent) {
		emit('eventClick', event)
		return
	}

	// Calculate position from DOM event if available
	if (domEvent) {
		const rect = (domEvent.currentTarget as HTMLElement).getBoundingClientRect()
		const position = {
			top: rect.top + window.scrollY + (rect.height / 2),
			left: rect.left + window.scrollX + rect.width + 10
		}
		emit('openPopover', event, position)
	} else {
		emit('openPopover', event)
	}
}

// Lifecycle hooks
onMounted(() => {
	document.addEventListener('mousedown', handleMouseDown)

	// Initialize current time indicator and set up interval to update it
	updateCurrentTimeIndicator()
	currentTimeInterval.value = setInterval(updateCurrentTimeIndicator, 60000)
})

onUnmounted(() => {
	document.removeEventListener('mousedown', handleMouseDown)
	document.removeEventListener('mousemove', handleMouseMove)
	document.removeEventListener('mouseup', handleMouseUp)

	if (currentTimeInterval.value) {
		clearInterval(currentTimeInterval.value)
	}
})
</script>

<template>
	<div class="w-100p overflow-hidden m_overflow h-100p grid">
		<div class="border-bottom me-1 txt-center p-05 dayGrid">
			<div />
			<div>
				{{ formatDate(startDate) }}
			</div>
		</div>

		<div class="overflow h-100p pe-05">
			<div class="time-slots dayGrid border-end relative" @mousedown="handleMouseDown">
				<div class="time-column">
					<div
						v-for="slot in timeSlots" :key="slot.time"
						class="time-slot txt-light txt-12 color-gray bg-gray-light border-start"
						:style="{ height: `${slotHeight}px` }"
					>
						{{ slot.time }}
					</div>
				</div>
				<div class="events-column">
					<!-- Current time indicator -->
					<div v-if="isToday" class="absolute end w-100p z-2 flex pointer-events-none" :style="{ top: `${currentTimeTop}px` }">
						<div class="current-time-dot h-10px aspect-ratio-1 round bg-primary" />
						<div class="current-time-line w-100p bg-primary" />
					</div>

					<div
						v-for="event in processedEvents" :key="event.id"
						class="event absolute radius-05 overflow-hidden pointer transition z-1"
						:style="{
							top: `${event.top}px`,
							height: `${event.height}px`,
							backgroundColor: event.color || 'var(--bgl-primary)',
						}"
						@click.stop="handleEventSelection(event, $event)"
					>
						<div class="event-content">
							<div class="white-space ellipsis-1">
								{{ event.title }}
							</div>
							<div class="event-time opacity-8">
								{{ formatDate(new Date(event.start_time), { fmt: 'HH:mm' }) }} - {{ formatDate(new Date(event.end_time), { fmt: 'HH:mm' }) }}
							</div>
						</div>
					</div>
				</div>

				<!-- Drag selection preview -->
				<div
					v-if="dragState.isDragging && dragState.start && dragState.end"
					class="drag-preview absolute bg-primary-tint pointer-events-none z-1"
					:style="{
						top: `${Math.min(dragState.start.y, dragState.end.y)}px`,
						height: `${Math.abs(dragState.end.y - dragState.start.y)}px`,
						left: '10px',
						right: '10px',
					}"
				>
					<div class="color-primary txt-12 p-025">
						{{ dragState.startTime ? formatDate(dragState.startTime, { fmt: 'HH:mm' }) : '' }}
						-
						{{ dragState.endTime ? formatDate(dragState.endTime, { fmt: 'HH:mm' }) : '' }}
					</div>
				</div>
			</div>
		</div>

		<div class="border-bottom me-1" />
	</div>
</template>

<style scoped>
.dayGrid {
	display: grid;
	grid-template-columns: 5rem 1fr;
}

.time-column {
	width: 80px;
	flex-shrink: 0;
}

.events-column {
	flex-grow: 1;
	position: relative;
	border-inline-start: 1px solid var(--border-color);
	min-height: 100%; /* Ensure the column fills the full height */
}

.date-header {
	padding: 0.5rem;
	text-align: center;
}

.day-header .events-column {
	border-inline-start: 1px solid transparent;
}

.time-slot {
	height: 60px; /* Match this with the slotHeight variable */
	display: flex;
	align-items: flex-start; /* Align to top to match events */
	justify-content: center;
	padding: 0.5rem 0;
	box-sizing: border-box;
}

.time-slots {
	flex-grow: 1;
	display: flex;
	overflow: auto;
	position: relative;
}

.event {
	left: 10px;
	right: 10px;
	box-sizing: border-box;
}

.event:hover {
	z-index: 2;
	transform: scale(1.02);
}

.event-content {
	padding: 0.5rem;
	color: white;
	font-size: 0.9rem;
	height: 100%;
	overflow: hidden;
}

.event-title {
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.event-time {
	font-size: 0.8rem;
}

.drag-preview {
	border: 1px solid var(--bgl-primary);
	background-color: rgba(var(--bgl-primary-rgb), 0.1);
	box-sizing: border-box;
}

.current-time-line {
	height: 2px;
	background-color: var(--bgl-primary);
}

.current-time-dot {
	background-color: var(--bgl-primary);
	margin-right: -5px; /* Adjust dot position */
}
</style>
