<script setup lang="ts">
import { ref } from "vue";
import FullCalendar from "@fullcalendar/vue3";
import dayGridPlugin from "@fullcalendar/daygrid";
import timeGridPlugin from "@fullcalendar/timegrid";
import interactionPlugin from "@fullcalendar/interaction";
import type { CalendarOptions, EventClickArg, EventDropArg } from "@fullcalendar/core";
import type { DateClickArg, EventResizeDoneArg } from "@fullcalendar/interaction";
import { listEvents, updateEvent, type EventEntry } from "@/api/client";
import EventSlideOver from "@/components/EventSlideOver.vue";
import { useToastStore } from "@/stores/toast";

const toast = useToastStore();
const calendarRef = ref<InstanceType<typeof FullCalendar> | null>(null);

// Slide-over state
const slideOverEvent = ref<EventEntry | null>(null);  // null = create mode
const slideOverOpen = ref(false);
const slideOverDate = ref<string>("");

function openCreate(date: string) {
  slideOverEvent.value = null;
  slideOverDate.value = date;
  slideOverOpen.value = true;
}

function openEdit(event: EventEntry) {
  slideOverEvent.value = event;
  slideOverDate.value = "";
  slideOverOpen.value = true;
}

function closeSlideOver() {
  slideOverOpen.value = false;
}

// Event entry cache keyed by id for quick lookups when clicking FC events
const eventCache = new Map<number, EventEntry>();

function toFcEvent(e: EventEntry) {
  return {
    id: String(e.id),
    title: e.title,
    start: e.start_dt,
    end: e.end_dt ?? undefined,
    allDay: e.all_day,
    backgroundColor: e.color || undefined,
    borderColor: e.color || undefined,
    extendedProps: { entryId: e.id },
  };
}

async function loadEvents(
  fetchInfo: { startStr: string; endStr: string },
  successCallback: (events: object[]) => void,
  failureCallback: (error: Error) => void,
) {
  try {
    const entries = await listEvents(fetchInfo.startStr, fetchInfo.endStr);
    eventCache.clear();
    for (const e of entries) eventCache.set(e.id, e);
    successCallback(entries.map(toFcEvent));
  } catch (err) {
    failureCallback(err instanceof Error ? err : new Error(String(err)));
  }
}

function handleDateClick(arg: DateClickArg) {
  openCreate(arg.dateStr);
}

function handleEventClick(arg: EventClickArg) {
  const id = arg.event.extendedProps.entryId as number;
  const entry = eventCache.get(id);
  if (entry) openEdit(entry);
}

async function handleEventDrop(arg: EventDropArg) {
  const id = arg.event.extendedProps.entryId as number;
  const start_dt = arg.event.startStr;
  const end_dt = arg.event.endStr || undefined;
  try {
    const updated = await updateEvent(id, { start_dt, end_dt, all_day: arg.event.allDay });
    eventCache.set(id, updated);
  } catch {
    arg.revert();
    toast.show("Failed to move event", "error");
  }
}

async function handleEventResize(arg: EventResizeDoneArg) {
  const id = arg.event.extendedProps.entryId as number;
  const start_dt = arg.event.startStr;
  const end_dt = arg.event.endStr || undefined;
  try {
    const updated = await updateEvent(id, { start_dt, end_dt });
    eventCache.set(id, updated);
  } catch {
    arg.revert();
    toast.show("Failed to resize event", "error");
  }
}

function onCreated(entry: EventEntry) {
  eventCache.set(entry.id, entry);
  calendarRef.value?.getApi().addEvent(toFcEvent(entry));
  closeSlideOver();
}

function onUpdated(entry: EventEntry) {
  eventCache.set(entry.id, entry);
  // Replace the event in FullCalendar
  const api = calendarRef.value?.getApi();
  if (api) {
    const existing = api.getEventById(String(entry.id));
    if (existing) {
      existing.remove();
      api.addEvent(toFcEvent(entry));
    }
  }
  closeSlideOver();
}

function onDeleted(id: number) {
  eventCache.delete(id);
  const api = calendarRef.value?.getApi();
  if (api) {
    api.getEventById(String(id))?.remove();
  }
  closeSlideOver();
}

const calendarOptions: CalendarOptions = {
  plugins: [dayGridPlugin, timeGridPlugin, interactionPlugin],
  initialView: "dayGridMonth",
  timeZone: "local",
  editable: true,
  selectable: false,
  headerToolbar: {
    left: "prev,next today",
    center: "title",
    right: "dayGridMonth,timeGridWeek,timeGridDay",
  },
  events: loadEvents,
  dateClick: handleDateClick,
  eventClick: handleEventClick,
  eventDrop: handleEventDrop,
  eventResize: handleEventResize,
  height: "auto",
};
</script>

<template>
  <div class="calendar-view">
    <div class="cal-header">
      <h1 class="cal-title">Calendar</h1>
      <button class="btn-new-event" @click="openCreate(new Date().toISOString().slice(0, 10))">
        + New Event
      </button>
    </div>

    <div class="fc-wrapper">
      <FullCalendar ref="calendarRef" :options="calendarOptions" />
    </div>

    <EventSlideOver
      v-if="slideOverOpen"
      :event="slideOverEvent"
      :initial-date="slideOverDate"
      @close="closeSlideOver"
      @created="onCreated"
      @updated="onUpdated"
      @deleted="onDeleted"
    />
  </div>
</template>

<style scoped>
.calendar-view {
  max-width: 1200px;
  margin: 0 auto;
  padding: 1.5rem 1.5rem 3rem;
}

.cal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 1.25rem;
}

.cal-title {
  font-size: 1.5rem;
  font-weight: 700;
  margin: 0;
  color: var(--color-text, #e8e9f0);
}

.btn-new-event {
  background: linear-gradient(135deg, #6366f1, #4f46e5);
  color: #fff;
  border: none;
  border-radius: 8px;
  padding: 0.55rem 1.1rem;
  font-size: 0.9rem;
  font-weight: 600;
  cursor: pointer;
  transition: opacity 0.15s;
}
.btn-new-event:hover { opacity: 0.88; }

.fc-wrapper {
  background: var(--color-surface, #1a1b1e);
  border: 1px solid var(--color-border, #2a2b30);
  border-radius: var(--radius-lg, 18px);
  padding: 1rem;
  overflow: hidden;
}

/* FullCalendar dark theme overrides */
:deep(.fc) {
  color: var(--color-text, #e8e9f0);
  font-family: inherit;
}
:deep(.fc-toolbar-title) {
  font-size: 1.1rem;
  font-weight: 600;
}
:deep(.fc-button) {
  background: var(--color-input-bg, #111113);
  border: 1px solid var(--color-border, #2a2b30);
  color: var(--color-text-muted, #888);
  font-size: 0.82rem;
  padding: 0.3rem 0.7rem;
  box-shadow: none;
}
:deep(.fc-button:hover),
:deep(.fc-button-active) {
  background: var(--color-primary, #6366f1) !important;
  border-color: var(--color-primary, #6366f1) !important;
  color: #fff !important;
}
:deep(.fc-button:focus) { box-shadow: none !important; }
:deep(.fc-daygrid-day-number),
:deep(.fc-col-header-cell-cushion) {
  color: var(--color-text-muted, #888);
  text-decoration: none;
  font-size: 0.82rem;
}
:deep(.fc-daygrid-day.fc-day-today) {
  background: rgba(99, 102, 241, 0.08);
}
:deep(.fc-event) {
  border-radius: 4px;
  border: none;
  padding: 1px 4px;
  font-size: 0.78rem;
  cursor: pointer;
}
:deep(.fc-event-main) { color: #fff; }
:deep(.fc-event:not([style*="background"])) {
  background: var(--color-primary, #6366f1);
}
:deep(.fc-daygrid-day-frame) { min-height: 5rem; }
:deep(.fc-scrollgrid) { border-color: var(--color-border, #2a2b30); }
:deep(.fc-scrollgrid td),
:deep(.fc-scrollgrid th) { border-color: var(--color-border, #2a2b30); }
:deep(.fc-daygrid-day) { cursor: pointer; }
:deep(.fc-daygrid-day:hover) { background: rgba(255,255,255,0.03); }
</style>
