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

interface WeekViewEvent extends CalendarEvent {
	top: number
	height: number
	left: number
	width: number
	overlappingEvents: number
	position: number
}

const props = withDefaults(defineProps<{
	events?: CalendarEvent[]
	startDate?: Date
	weekStart?: WeekStart
	availabilityMode?: boolean
	availabilityEditable?: boolean
	availabilitySlots?: AvailabilitySlot[]
}>(), {
	startDate: () => new Date(),
	weekStart: 'Sunday',
	events: () => [],
	availabilityMode: false,
	availabilityEditable: false,
	availabilitySlots: () => []
})

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
	(e: 'availabilityChange', slots: AvailabilitySlot[]): void
}>()

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

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

// Check if drag-to-create is enabled based on whether eventCreate handler is provided
const isDragToCreateEnabled = computed(() => {
	return !!slots.eventCreate || Object.prototype.hasOwnProperty.call(emit, 'eventCreate')
})

// Drag state
const dragState = ref({
	isDragging: false,
	startDay: -1, // Index of the starting day
	endDay: -1, // Index of the ending day
	start: undefined as { x: number, y: number } | undefined,
	end: undefined as { x: number, y: number } | undefined,
	startTime: undefined as Date | undefined,
	endTime: undefined as Date | undefined
})

// ===== AVAILABILITY MODE =====
const AVAILABILITY_SNAP_MINUTES = 30
const localAvailability = ref<AvailabilitySlot[]>([])
const availDragState = ref({
	isDragging: false,
	mode: 'add' as 'add' | 'remove',
	dayIndex: -1,
	startMinute: 0,
	currentMinute: 0
})

// Sync external availability slots to local state
watch(() => props.availabilitySlots, (slots) => {
	localAvailability.value = slots.map(s => ({
		start_time: new Date(s.start_time),
		end_time: new Date(s.end_time)
	}))
}, { immediate: true })

// Calculate week days based on start date and week start preference
const weekDays = computed(() => {
	const days = []
	const start = new Date(props.startDate)
	const weekStartOffset = props.weekStart === 'Sunday' ? 0 : 1

	// Adjust to start of week
	const dayOfWeek = start.getDay()
	start.setDate(start.getDate() - dayOfWeek + weekStartOffset)
	start.setHours(0, 0, 0, 0) // Set time to start of day

	// Create array of 7 day dates
	for (let i = 0; i < 7; i++) {
		const date = new Date(start)
		date.setDate(start.getDate() + i)
		days.push(date)
	}
	return days
})

function snapMinutes(minutes: number): number {
	return Math.round(minutes / AVAILABILITY_SNAP_MINUTES) * AVAILABILITY_SNAP_MINUTES
}

function getAvailabilitySlotsForDay(day: Date) {
	return localAvailability.value.filter((slot) => {
		const slotDate = new Date(slot.start_time)
		return slotDate.getFullYear() === day.getFullYear()
			&& slotDate.getMonth() === day.getMonth()
			&& slotDate.getDate() === day.getDate()
	}).map((slot) => {
		const startMinutes = new Date(slot.start_time).getHours() * 60 + new Date(slot.start_time).getMinutes()
		const endMinutes = new Date(slot.end_time).getHours() * 60 + new Date(slot.end_time).getMinutes()
		return {
			top: (startMinutes / slotDuration) * slotHeight,
			height: ((endMinutes - startMinutes) / slotDuration) * slotHeight,
			slot
		}
	})
}

function availabilityPreviewForDay(dayIndex: number) {
	if (!availDragState.value.isDragging || availDragState.value.dayIndex !== dayIndex) return null
	const minM = Math.min(availDragState.value.startMinute, availDragState.value.currentMinute)
	const maxM = Math.max(availDragState.value.startMinute, availDragState.value.currentMinute)
	return {
		top: (minM / slotDuration) * slotHeight,
		height: ((maxM - minM) / slotDuration) * slotHeight,
		mode: availDragState.value.mode
	}
}

function isMinuteInAvailability(day: Date, minute: number): boolean {
	return localAvailability.value.some((slot) => {
		const slotDate = new Date(slot.start_time)
		if (slotDate.getFullYear() !== day.getFullYear()
			|| slotDate.getMonth() !== day.getMonth()
			|| slotDate.getDate() !== day.getDate()) { return false
		}
		const startM = slotDate.getHours() * 60 + slotDate.getMinutes()
		const endM = new Date(slot.end_time).getHours() * 60 + new Date(slot.end_time).getMinutes()
		return minute >= startM && minute < endM
	})
}

function handleAvailMouseDown(e: MouseEvent, dayIndex: number) {
	if (!props.availabilityEditable) return
	e.preventDefault()
	e.stopPropagation()
	const day = weekDays.value[dayIndex]
	const minutes = snapMinutes(getMinutesFromY(e.clientY))
	const isExisting = isMinuteInAvailability(day, minutes)

	availDragState.value = {
		isDragging: true,
		mode: isExisting ? 'remove' : 'add',
		dayIndex,
		startMinute: minutes,
		currentMinute: minutes + AVAILABILITY_SNAP_MINUTES
	}

	document.addEventListener('mousemove', handleAvailMouseMove)
	document.addEventListener('mouseup', handleAvailMouseUp)
}

function handleAvailMouseMove(e: MouseEvent) {
	if (!availDragState.value.isDragging) return
	const minutes = snapMinutes(getMinutesFromY(e.clientY))
	availDragState.value.currentMinute = minutes
}

function handleAvailMouseUp() {
	if (!availDragState.value.isDragging) return
	const { dayIndex, startMinute, currentMinute, mode } = availDragState.value
	const day = weekDays.value[dayIndex]
	const minM = Math.min(startMinute, currentMinute)
	const maxM = Math.max(startMinute, currentMinute)

	if (maxM - minM < AVAILABILITY_SNAP_MINUTES) {
		availDragState.value.isDragging = false
		document.removeEventListener('mousemove', handleAvailMouseMove)
		document.removeEventListener('mouseup', handleAvailMouseUp)
		return
	}

	const newStart = new Date(day)
	newStart.setHours(Math.floor(minM / 60), minM % 60, 0, 0)
	const newEnd = new Date(day)
	newEnd.setHours(Math.floor(maxM / 60), maxM % 60, 0, 0)

	if (mode === 'add') {
		// Add and merge overlapping
		const otherDays = localAvailability.value.filter((s) => {
			const d = new Date(s.start_time)
			return d.getFullYear() !== day.getFullYear()
				|| d.getMonth() !== day.getMonth()
				|| d.getDate() !== day.getDate()
		})
		const sameDaySlots = localAvailability.value.filter((s) => {
			const d = new Date(s.start_time)
			return d.getFullYear() === day.getFullYear()
				&& d.getMonth() === day.getMonth()
				&& d.getDate() === day.getDate()
		})
		sameDaySlots.push({ start_time: newStart, end_time: newEnd })
		// Sort and merge
		sameDaySlots.sort((a, b) => new Date(a.start_time).getTime() - new Date(b.start_time).getTime())
		const merged: AvailabilitySlot[] = []
		for (const s of sameDaySlots) {
			if (merged.length === 0) {
				merged.push({ start_time: new Date(s.start_time), end_time: new Date(s.end_time) })
			} else {
				const last = merged[merged.length - 1]
				if (new Date(s.start_time).getTime() <= new Date(last.end_time).getTime()) {
					last.end_time = new Date(Math.max(new Date(last.end_time).getTime(), new Date(s.end_time).getTime()))
				} else {
					merged.push({ start_time: new Date(s.start_time), end_time: new Date(s.end_time) })
				}
			}
		}
		localAvailability.value = [...otherDays, ...merged]
	} else {
		// Remove: subtract the range from existing slots
		const result: AvailabilitySlot[] = []
		for (const s of localAvailability.value) {
			const d = new Date(s.start_time)
			if (d.getFullYear() !== day.getFullYear()
				|| d.getMonth() !== day.getMonth()
				|| d.getDate() !== day.getDate()) {
				result.push(s)
				continue
			}
			const sStart = new Date(s.start_time).getTime()
			const sEnd = new Date(s.end_time).getTime()
			const rStart = newStart.getTime()
			const rEnd = newEnd.getTime()

			// No overlap
			if (sEnd <= rStart || sStart >= rEnd) {
				result.push(s)
				continue
			}
			// Left remainder
			if (sStart < rStart) {
				result.push({ start_time: new Date(sStart), end_time: new Date(rStart) })
			}
			// Right remainder
			if (sEnd > rEnd) {
				result.push({ start_time: new Date(rEnd), end_time: new Date(sEnd) })
			}
		}
		localAvailability.value = result
	}

	emit('availabilityChange', localAvailability.value)
	availDragState.value.isDragging = false
	document.removeEventListener('mousemove', handleAvailMouseMove)
	document.removeEventListener('mouseup', handleAvailMouseUp)
}

// Time indicators
const currentTimeTop = ref(0)
const isToday = ref(false)
const currentTimeInterval = ref<any>()

const timeSlotsContainer = ref<HTMLElement>()
const calendarGrid = ref<HTMLElement>()
const dayColumns = ref<HTMLElement[]>([])
const dayColumnsContainer = ref<HTMLElement>()
const scrollableContainer = ref<HTMLElement>()

function getMinutesFromY(clientY: number): number {
	if (!dayColumnsContainer.value) return 0
	const rect = dayColumnsContainer.value.getBoundingClientRect()
	const relativeY = clientY - rect.top
	return Math.max(0, Math.min((relativeY / slotHeight) * slotDuration, 24 * 60))
}

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

// Calculate drag preview positioning using the same formula as events
const dragPreviewPosition = computed(() => {
	if (!dragState.value.isDragging || !dragState.value.startTime || !dragState.value.endTime) {
		return null
	}

	// Use the exact same calculation as events
	const startMinutes = dragState.value.startTime.getHours() * 60 + dragState.value.startTime.getMinutes()
	const endMinutes = dragState.value.endTime.getHours() * 60 + dragState.value.endTime.getMinutes()

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

	return { top, height }
})

// Process events for display with positioning calculations
const processedEvents = computed(() => {
	const events: WeekViewEvent[] = []
	const dayEvents: { [dayIndex: number]: WeekViewEvent[] } = {}

	// First pass: group events by day and calculate basic positioning
	props.events.forEach((event) => {
		const startDate = new Date(event.start_time)
		const endDate = new Date(event.end_time)

		// Find which day this event belongs to
		const dayIndex = weekDays.value.findIndex(day => day.getDate() === startDate.getDate()
			&& day.getMonth() === startDate.getMonth()
			&& day.getFullYear() === startDate.getFullYear()
		)

		if (dayIndex === -1) { return }

		// Calculate vertical positioning
		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)

		const weekEvent: WeekViewEvent = {
			...event,
			top,
			height,
			left: 0,
			width: 100,
			overlappingEvents: 0,
			position: 0
		}

		if (!dayEvents[dayIndex]) {
			dayEvents[dayIndex] = []
		}
		dayEvents[dayIndex].push(weekEvent)
	})

	// Second pass: detect and handle overlapping events for each day
	Object.entries(dayEvents).forEach(([_, dayEventList]) => {
		// Sort events by start time
		dayEventList.sort((a, b) => new Date(a.start_time).getTime() - new Date(b.start_time).getTime())

		// Group overlapping events
		const overlappingGroups: WeekViewEvent[][] = []
		let currentGroup: WeekViewEvent[] = []

		dayEventList.forEach((event) => {
			if (currentGroup.length === 0) {
				currentGroup = [event]
			} else {
				// Check if this event overlaps with any event in the current group
				const overlaps = currentGroup.some((groupEvent) => {
					const eventStart = new Date(event.start_time).getTime()
					const eventEnd = new Date(event.end_time).getTime()
					const groupEventStart = new Date(groupEvent.start_time).getTime()
					const groupEventEnd = new Date(groupEvent.end_time).getTime()

					return !(eventEnd <= groupEventStart || eventStart >= groupEventEnd)
				})

				if (overlaps) {
					currentGroup.push(event)
				} else {
					// No overlap, finalize current group and start new one
					if (currentGroup.length > 0) {
						overlappingGroups.push([...currentGroup])
					}
					currentGroup = [event]
				}
			}
		})

		// Don't forget the last group
		if (currentGroup.length > 0) {
			overlappingGroups.push(currentGroup)
		}

		// Position overlapping events with elegant spacing
		overlappingGroups.forEach((group) => {
			if (group.length > 1) {
				// Add some spacing between overlapping events (2% gap)
				const gap = 2
				const availableWidth = 100 - (gap * (group.length - 1))
				const eventWidth = availableWidth / group.length

				group.forEach((event, index) => {
					event.overlappingEvents = group.length
					event.position = index
					event.width = eventWidth
					event.left = index * (eventWidth + gap)
				})
			}
			events.push(...group)
		})
	})

	return events
})

// Mouse event handlers for drag-to-create functionality
function handleMouseDown(e: MouseEvent, day: Date) {
	// Only allow drag-to-create if the feature is enabled
	if (!isDragToCreateEnabled.value) { return }

	if (!calendarGrid.value || !dayColumnsContainer.value) { return }

	// Find the clicked day column
	let clickedDayIndex = -1
	for (let i = 0; i < dayColumns.value.length; i++) {
		const columnEl = dayColumns.value[i]
		if (!columnEl) { continue }

		const rect = columnEl.getBoundingClientRect()
		if (e.clientX >= rect.left && e.clientX <= rect.right) {
			clickedDayIndex = i
			break
		}
	}

	if (clickedDayIndex === -1) { return }

	// Get the clicked day column's position and dimensions
	const dayColumnRect = dayColumns.value[clickedDayIndex].getBoundingClientRect()
	const dayColumnsRect = dayColumnsContainer.value.getBoundingClientRect()

	dragState.value.isDragging = true
	dragState.value.startDay = clickedDayIndex
	dragState.value.endDay = clickedDayIndex
	dragState.value.start = {
		x: dayColumnRect.left - dayColumnsRect.left, // Left edge of the day column
		y: e.clientY - dayColumnsRect.top
	}
	dragState.value.end = {
		x: dayColumnRect.right - dayColumnsRect.left, // Right edge of the day column
		y: e.clientY - dayColumnsRect.top
	}

	// Use the same positioning calculation as events for consistency
	const startTime = getTimeFromPositionConsistent(e.clientY, day)
	dragState.value.startTime = startTime

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

function handleMouseMove(e: MouseEvent) {
	if (!isDragToCreateEnabled.value || !dragState.value.isDragging || !dragState.value.start || !dayColumns.value.length || !calendarGrid.value || !dayColumnsContainer.value) { return }

	// Find which day column we're hovering over
	let targetDayIndex = -1
	for (let i = 0; i < dayColumns.value.length; i++) {
		const columnEl = dayColumns.value[i]
		if (!columnEl) { continue }

		const rect = columnEl.getBoundingClientRect()
		if (e.clientX >= rect.left && e.clientX <= rect.right) {
			targetDayIndex = i
			break
		}
	}

	if (targetDayIndex === -1) { return }

	// Update which days are selected
	dragState.value.endDay = targetDayIndex
	dragState.value.end = {
		x: dragState.value.start!.x, // Keep x position bound to starting day column
		y: e.clientY - dayColumnsContainer.value.getBoundingClientRect().top
	}

	if (targetDayIndex >= 0 && targetDayIndex < weekDays.value.length) {
		// Always use the starting day as the base date for the event
		const startDay = new Date(weekDays.value[dragState.value.startDay])
		startDay.setHours(0, 0, 0, 0)

		// Calculate end time based on mouse position but on the starting day
		// Use the consistent positioning function for perfect alignment
		const endTime = getTimeFromPositionConsistent(e.clientY, startDay)
		dragState.value.endTime = endTime
	}
}

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

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

	// Always use the starting day for the event, but allow time selection across days
	// The event will be created on the starting day with the selected time range
	if (end < start) {
		// If end time is before start time, swap them but keep the starting day
		[start, end] = [end, start]
	}

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

	// Reset drag state
	dragState.value = {
		isDragging: false,
		startDay: -1,
		endDay: -1,
		start: undefined,
		end: undefined,
		startTime: undefined,
		endTime: undefined
	}

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

// Consistent time positioning function that uses the same coordinate system as events
function getTimeFromPositionConsistent(y: number, day: Date): Date {
	if (!dayColumnsContainer.value) { return new Date(day) }

	const containerRect = dayColumnsContainer.value.getBoundingClientRect()

	// Calculate relative Y position from the container (same as events use)
	const relativeY = y - containerRect.top

	// Use the exact same formula as events
	const minutesPerSlot = slotDuration
	const slotsFromTop = relativeY / slotHeight
	const minutes = Math.floor(slotsFromTop * minutesPerSlot)

	const date = new Date(day)
	date.setHours(Math.floor(minutes / 60))
	const roundedMinutes = Math.round((minutes % 60) / 5) * 5
	date.setMinutes(roundedMinutes)
	date.setSeconds(0)
	date.setMilliseconds(0)

	return date
}

// Update the current time indicator to use the same calculation as events
function updateCurrentTimeIndicator() {
	const now = new Date()

	// Check if today is in our current week view
	isToday.value = weekDays.value.some(day => day.getDate() === now.getDate()
		&& day.getMonth() === now.getMonth()
		&& day.getFullYear() === now.getFullYear()
	)

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

// Update the 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)
	}
}

function setDayColumnRef(el: Element | ComponentPublicInstance | null | undefined, index: number) {
	// Ensure the array is the right size
	while (dayColumns.value.length <= index) {
		dayColumns.value.push(null as unknown as HTMLElement)
	}

	if (el) {
		dayColumns.value[index] = el instanceof Element ? el as HTMLElement : (el.$el as HTMLElement)
	} else {
		// If el is undefined or null, we might still want to keep track of this slot
		dayColumns.value[index] = null as unknown as HTMLElement
	}
}

function scrollToTime(time: number) {
	if (scrollableContainer.value) {
		scrollableContainer.value.scrollTop = time * slotHeight
	}
}

// Lifecycle hooks
onMounted(() => {
	updateCurrentTimeIndicator()
	currentTimeInterval.value = setInterval(updateCurrentTimeIndicator, 60000)

	// Scroll to 6:00 AM on mount
	nextTick(() => { scrollToTime(6) })
})

onUnmounted(() => {
	document.removeEventListener('mousemove', handleMouseMove)
	document.removeEventListener('mouseup', handleMouseUp)
	document.removeEventListener('mousemove', handleAvailMouseMove)
	document.removeEventListener('mouseup', handleAvailMouseUp)

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

<template>
	<div class="w-100p overflow-hidden m_overflow h-100p grid">
		<div ref="calendarGrid" class="weekGrid border-bottom me-1">
			<div />
			<div v-for="day in weekDays" :key="day.toISOString()" class="day-header p-05 txt-center m_txt12">
				{{ formatDate(day, { format: 'DDD' }) }}
				<span
					class="txt-12 round p-025" :class="{
						'color-gray': day.toDateString() !== new Date().toDateString(),
						'bg-primary color-white': day.toDateString() === new Date().toDateString(),
					}"
				>
					{{ formatDate(day, { format: 'DD' }) }}
				</span>
			</div>
		</div>
		<div ref="scrollableContainer" class="overflow h-100p pe-05">
			<div ref="dayColumnsContainer" class="weekGrid border-end relative">
				<div ref="timeSlotsContainer">
					<div
						v-for="slot in timeSlots" :key="slot.time"
						class="txt-light txt-12 color-gray flex justify-content-center bg-gray-light border-start"
						:style="{ height: `${slotHeight}px` }"
					>
						{{ slot.time }}
					</div>
				</div>

				<!-- Current time indicator - ensure it aligns with the time slots and events -->
				<div
					v-if="isToday" class="absolute end w-100p z-2 flex pointer-events-none ps-4-5"
					: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="(day, index) in weekDays" :key="day.toISOString()" :ref="el => setDayColumnRef(el, index)"
					class="day-column top bottom border-start relative"
					@mousedown="props.availabilityEditable ? handleAvailMouseDown($event, index) : handleMouseDown($event, day)"
				>
					<!-- Hour grid lines -->
					<template v-for="slot in timeSlots" :key="`line-${slot.time}`">
						<div
							class="hour-line absolute start end pointer-events-none"
							:style="{ top: `${slot.hour * slotHeight}px` }"
						/>
						<div
							class="sub-hour-line absolute start end pointer-events-none"
							:style="{ top: `${slot.hour * slotHeight + slotHeight / 3}px` }"
						/>
						<div
							class="sub-hour-line absolute start end pointer-events-none"
							:style="{ top: `${slot.hour * slotHeight + (slotHeight * 2) / 3}px` }"
						/>
					</template>

					<!-- Availability painted blocks (behind events) -->
					<template v-if="props.availabilityMode">
						<div
							v-for="(block, bi) in getAvailabilitySlotsForDay(day)" :key="`avail-${bi}`"
							class="availability-block absolute start end"
							:class="{ 'availability-editable': props.availabilityEditable }"
							:style="{ top: `${block.top}px`, height: `${block.height}px` }"
						/>
						<!-- Availability drag preview -->
						<div
							v-if="availabilityPreviewForDay(index)"
							class="availability-preview absolute start end pointer-events-none"
							:class="{ 'avail-remove': availabilityPreviewForDay(index)!.mode === 'remove' }"
							:style="{
								top: `${availabilityPreviewForDay(index)!.top}px`,
								height: `${availabilityPreviewForDay(index)!.height}px`,
							}"
						/>
					</template>

					<template
						v-for="event in processedEvents.filter(e =>
							new Date(e.start_time).toDateString() === day.toDateString())" :key="event.id"
					>
						<div
							class="event absolute radius-05 overflow-hidden pointer transition z-1 opacity-8 border"
							:style="{
								top: `${event.top}px`,
								height: `${event.height}px`,
								left: `${event.left}%`,
								width: `${event.width}%`,
								backgroundColor: event.color || 'var(--bgl-primary)',
							}" @mousedown.stop @click.stop="handleEventSelection(event, $event)"
						>
							<div class="overflow-hidden color-white p-025 txt12 h-100p flex gap-1 flex-wrap">
								<div class="white-space ellipsis-1">
									{{ event.title }}
								</div>
								<div class="txt10 opacity-8 user-select-none">
									{{ formatDate(event.start_time, { format: 'HH:mm' }) }} - {{ formatDate(event.end_time,
										{ format: 'HH:mm' }) }}
								</div>
							</div>
						</div>
					</template>
				</div>

				<!-- Drag selection preview - ensure it aligns with time slots and events -->
				<div
					v-if="isDragToCreateEnabled && dragState.isDragging && dragState.start && dragState.end && dragPreviewPosition"
					class="drag-preview absolute bg-primary-tint pointer-events-none overflow-hidden opacity-7 z-1"
					:style="{
						left: `${dragState.start.x}px`,
						top: `${dragPreviewPosition.top}px`,
						width: `${dayColumns[dragState.startDay]?.offsetWidth || 100}px`,
						height: `${dragPreviewPosition.height}px`,
					}"
				>
					<div class="color-primary txt-12 p-025">
						{{ dragState.startTime ? formatDate(dragState.startTime, { format: 'HH:mm' }) : '' }} - {{
							dragState.endTime
								? formatDate(dragState.endTime, { format: 'HH:mm' }) : '' }}
					</div>
				</div>
			</div>
		</div>
		<div class="border-bottom me-1" />
	</div>
</template>

<style scoped>

.weekGrid {
display: grid;
grid-template-columns: 5rem repeat(7, 1fr);
}

.days-column {
flex-grow: 1;
display: flex;
}

.day-column {
flex: 1;
position: relative;
/* Ensure absolute positioning works properly */
min-height: 100%;
/* Ensure column fills the full height */
}

/* Add consistent styling for the time slots */
.txt-light {
padding: 0.5rem 0;
box-sizing: border-box;
display: flex;
align-items: flex-start;
justify-content: center;
}

.event {
margin-right: 2px;
box-sizing: border-box;
}

.event:hover {
z-index: 2;
}

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

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

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

.hour-line {
border-top: 1px solid var(--bgl-gray-80);
z-index: 0;
height: 0;
}

.sub-hour-line {
border-top: 1px dashed var(--bgl-gray-30, #e8e8e8);
z-index: 0;
height: 0;
}

/* This ensures all grid content aligns properly */
.overflow {
position: relative;
}

/* Time column headers should be aligned with their content */
.day-header {
/* box-sizing: border-box;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center; */
}

.availability-block {
background-color: rgba(76, 175, 80, 0.18);
border-inline-start: 3px solid rgba(76, 175, 80, 0.5);
z-index: 0;
pointer-events: none;
}

.availability-block.availability-editable {
background-color: rgba(33, 150, 243, 0.18);
border-inline-start: 3px solid rgba(33, 150, 243, 0.5);
}

.availability-preview {
background-color: rgba(76, 175, 80, 0.25);
border: 1px dashed rgba(76, 175, 80, 0.6);
z-index: 0;
}

.availability-preview.avail-remove {
background-color: rgba(244, 67, 54, 0.15);
border-color: rgba(244, 67, 54, 0.5);
}

@media (max-width: 910px) {
.weekGrid {
	display: grid;
	grid-template-columns: 3rem repeat(7, 100px);
}
}

</style>
