<script setup lang="ts">
import type { Component } from 'vue'
import type { CalendarEvent, CalendarProps, CalendarView, CalendarViewState } from './CalendarTypes'
import { timeDelta, Btn, ListItem, Dropdown, fmtDate } from '@bagelink/vue'
import { ref, computed, onMounted } from 'vue'
import CalendarPopover from './CalendarPopover.vue'
import AgendaView from './views/AgendaView.vue'
import DayView from './views/DayView.vue'
import MonthView from './views/MonthView.vue'
import WeekView from './views/WeekView.vue'

const props = withDefaults(defineProps<CalendarProps>(), {
	startDate: () => new Date(),
	view: 'Week',
	weekStart: 'Sunday',
	events: () => []
})

const emit = defineEmits<{
	(e: 'eventClick', event: CalendarEvent): void
	(e: 'eventCreate', event: { start_time: Date, end_time: Date }): void
	(e: 'eventUpdate', event: CalendarEvent): void
	(e: 'eventDelete', eventId: string): void
	(e: 'dateChange', changeEvent: CalendarViewState): void
	(e: 'viewChange', changeEvent: CalendarViewState): void
	(e: 'ready', changeEvent: CalendarViewState): void
}>()

const currentDate = ref(new Date(props.startDate))
const currentView = ref(props.view)
const activeEvent = ref<CalendarEvent>()
const showPopover = ref(false)
const popoverPosition = ref<{ top: number, left: number }>()

const views: Record<CalendarView, Component> = {
	Week: WeekView,
	Month: MonthView,
	Day: DayView,
	Agenda: AgendaView
}

const visibleDateRange = computed(() => {
	const start = new Date(currentDate.value)
	let end = new Date(currentDate.value)
	const addSunday = props.weekStart === 'Sunday' ? 0 : 1
	switch (currentView.value) {
		case 'Week':
			start.setDate(start.getDate() - start.getDay() + addSunday)
			end.setDate(start.getDate() + 6)
			break
		case 'Month':
		case 'Agenda':
			start.setDate(-6)
			end = new Date(start.getFullYear(), start.getMonth() + 2, 7)
			break
		case 'Day':
			end.setDate(end.getDate() + 1)
			break
		default:
			console.error(`Invalid view: ${currentView.value}`)
	}
	return { start, end }
})

const state = computed<CalendarViewState>(() => ({
	visibleDateRange: visibleDateRange.value,
	currentDate: currentDate.value,
	currentView: currentView.value
}))

function handleDateChange(date: Date) {
	console.log('handleDateChange', date)
	currentDate.value = new Date(date)
	emit('dateChange', state.value)
}

function handleViewChange(view: CalendarView) {
	currentView.value = view
	emit('viewChange', state.value)
}

// Event handlers
function handleEventClick(event: CalendarEvent) {
	emit('eventClick', event)
}

function handleEventCreate(event: { start_time: Date, end_time: Date }) {
	emit('eventCreate', event)
}

function handleEventUpdate(event: CalendarEvent) {
	emit('eventUpdate', event)
}

function handleEventDelete(eventId: string) {
	emit('eventDelete', eventId)
}

// Popover handling
function openPopover(event: CalendarEvent, position?: { top: number, left: number }) {
	activeEvent.value = event
	popoverPosition.value = position
	showPopover.value = true
}

function closePopover() {
	showPopover.value = false
	activeEvent.value = undefined
	popoverPosition.value = undefined
}

defineExpose({
	visibleDateRange,
	currentView,
	currentDate,
	openPopover,
	closePopover
})

onMounted(() => { emit('ready', state.value) })
</script>

<template>
	<div class="calendar">
		<div class="flex m_block m_pb-1">
			<h3 class="txt-light my-0">
				<b>{{ fmtDate(currentDate, { fmt: 'MMMM' }) }}</b>
				{{ fmtDate(currentDate, { fmt: 'YYYY' }) }}
			</h3>
			<div class="ms-auto flex gap-025">
				<Dropdown thin :value="currentView" iconEnd="keyboard_arrow_down" color="gray">
					<ListItem
						v-for="(_, key) in views"
						:key="key"
						:title="key"
						@click="handleViewChange(key)"
					/>
				</Dropdown>
				<Btn icon="calendar" thin color="gray" value="Today" @click="handleDateChange(new Date())" />
				<Btn
					icon="chevron_left"
					color="gray"
					thin
					@click="handleDateChange(timeDelta(currentDate, { [currentView]: -1 }))"
				/>
				<Btn
					icon="chevron_right"
					color="gray"
					thin
					@click="handleDateChange(timeDelta(currentDate, { [currentView]: 1 }))"
				/>
			</div>
		</div>
		<component
			:is="views[currentView]"
			:events="events"
			:start-date="currentDate"
			:week-start="weekStart"
			@event-click="handleEventClick"
			@event-create="handleEventCreate"
			@event-update="handleEventUpdate"
			@event-delete="handleEventDelete"
			@date-change="handleDateChange"
			@open-popover="openPopover"
		>
			<template #eventContent="{ event }">
				<slot name="eventContent" :event="event" />
			</template>
		</component>

		<!-- Global Popover -->
		<CalendarPopover
			:event="activeEvent"
			:position="popoverPosition"
			:show="showPopover"
			:has-event-content-slot="!!$slots.eventContent"
			@close="closePopover"
			@event-click="handleEventClick"
		>
			<template #eventContent="{ event }">
				<slot name="eventContent" :event="event" />
			</template>
		</CalendarPopover>
	</div>
</template>

<style scoped>
.calendar {
  display: flex;
  flex-direction: column;
  height: 100%;
  width: 100%;
}
</style>
