"use client"

import { useCallback, useEffect, useMemo, useRef, useState } from "react"
import { useParams, useRouter, useSearchParams } from "next/navigation"
import { addDays, addHours, addMinutes, addMonths, startOfHour } from "date-fns"
import { AgendaEventDialog, type AgendaEventDialogState } from "@/components/agenda/agenda-event-dialog"
import { AgendaEventPopover, type AgendaEventPopoverState } from "@/components/agenda/agenda-event-popover"
import type { AnchorRect } from "@/components/agenda/agenda-floating-card"
import { AgendaHeader } from "@/components/agenda/agenda-header"
import { AgendaQuickCreate, type AgendaQuickCreateState } from "@/components/agenda/agenda-quick-create"
import { AgendaSidebar } from "@/components/agenda/agenda-sidebar"
import { AgendaViewMonth } from "@/components/agenda/agenda-view-month"
import { AgendaViewWeek } from "@/components/agenda/agenda-view-week"
import { Skeleton } from "@/components/ui/skeleton"
import { useAgendaEvents } from "@/lib/api/hooks/use-calendar-queries"
import { isExternalCalendarId } from "@/lib/agenda/agenda-calendar-visibility"
import { parseICSDate, viewDays, viewRange } from "@/lib/agenda/agenda-date"
import { useExternalAgendaEvents } from "@/lib/agenda/use-external-agenda-events"
import { useResolvedWeekStartsOn } from "@/lib/agenda/use-resolved-week-start"
import { draftToPendingEvent } from "@/lib/agenda/agenda-pending-event"
import { useAgendaSettingsStore } from "@/lib/agenda/agenda-store"
import { useAgendaEventMove } from "@/lib/agenda/use-agenda-event-move"
import { useVisibleAgendaCalendars } from "@/lib/agenda/use-visible-agenda-calendars"
import type { AgendaEvent, AgendaEventDraft } from "@/lib/agenda/agenda-types"
import { useAgendaRouteRoot } from "@/lib/agenda/agenda-route-context"
import {
  buildAgendaPath,
  parseAgendaSegments,
  type AgendaView,
} from "@/lib/agenda/agenda-url"
import { useChromeIdentity } from "@/lib/hooks/use-chrome-identity"
import { useIsMobile } from "@/hooks/use-mobile"
import { AGENDA_CALENDAR_CARD_CLASS, AGENDA_MAIN_INSET_X } from "@/lib/agenda/agenda-chrome-classes"
import { cn } from "@/lib/utils"

export function AgendaPage() {
  const router = useRouter()
  const params = useParams()
  const searchParams = useSearchParams()
  const agendaRouteRoot = useAgendaRouteRoot()
  const isMobile = useIsMobile()
  const identity = useChromeIdentity()

  const route = useMemo(
    () => parseAgendaSegments(params.segments as string[] | undefined),
    [params.segments],
  )
  const lastView = useAgendaSettingsStore((s) => s.lastView)
  const setLastView = useAgendaSettingsStore((s) => s.setLastView)
  const externalCalendars = useAgendaSettingsStore((s) => s.externalCalendars)
  const weekStart = useAgendaSettingsStore((s) => s.weekStart)
  const weekStartsOn = useResolvedWeekStartsOn(weekStart)
  const defaultQuickDurationMinutes = useAgendaSettingsStore(
    (s) => s.defaultQuickDurationMinutes,
  )

  const view: AgendaView = route.view ?? (isMobile ? "day" : lastView)
  const date = route.date

  useEffect(() => {
    if (!route.view) {
      router.replace(
        buildAgendaPath(view, date, agendaRouteRoot) + window.location.search
      )
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [route.view])

  useEffect(() => {
    if (route.view) setLastView(route.view)
  }, [route.view, setLastView])

  const navigate = useCallback(
    (nextView: AgendaView, nextDate: Date) => {
      router.push(buildAgendaPath(nextView, nextDate, agendaRouteRoot))
    },
    [router, agendaRouteRoot],
  )

  const step = useCallback(
    (delta: 1 | -1) => {
      const next =
        view === "month"
          ? addMonths(date, delta)
          : addDays(date, view === "week" ? delta * 7 : delta)
      navigate(view, next)
    },
    [view, date, navigate],
  )

  const {
    calendars,
    visibleCalendars,
    isLoading: calendarsLoading,
  } = useVisibleAgendaCalendars()

  const visibleApiCalendars = useMemo(
    () => visibleCalendars.filter((calendar) => !isExternalCalendarId(calendar.id)),
    [visibleCalendars],
  )
  const visibleExternalCalendars = useMemo(
    () => externalCalendars.filter((calendar) =>
      visibleCalendars.some((visible) => visible.id === calendar.id),
    ),
    [externalCalendars, visibleCalendars],
  )

  const writableCalendars = useMemo(
    () => calendars.filter((calendar) => !isExternalCalendarId(calendar.id)),
    [calendars],
  )
  const writableVisibleCalendars = useMemo(
    () => visibleCalendars.filter((calendar) => !isExternalCalendarId(calendar.id)),
    [visibleCalendars],
  )

  const fetchRange = useMemo(
    () => viewRange("month", date, weekStart, weekStartsOn),
    [date, weekStart, weekStartsOn],
  )
  const { events: apiEvents } = useAgendaEvents(
    visibleApiCalendars,
    fetchRange.start,
    fetchRange.end,
  )
  const { events: externalEvents } = useExternalAgendaEvents(
    visibleExternalCalendars,
    fetchRange.start,
    fetchRange.end,
  )
  const events = useMemo(
    () =>
      [...apiEvents, ...externalEvents].sort(
        (a, b) => a.start.getTime() - b.start.getTime(),
      ),
    [apiEvents, externalEvents],
  )

  const [quickCreate, setQuickCreate] = useState<AgendaQuickCreateState | null>(null)
  const [dialogState, setDialogState] = useState<AgendaEventDialogState | null>(null)
  const [popover, setPopover] = useState<AgendaEventPopoverState | null>(null)
  /** Brouillon affiché sur la grille tant que la modale est ouverte. */
  const [pendingDraft, setPendingDraft] = useState<AgendaEventDraft | null>(null)

  const defaultCalendarId =
    writableVisibleCalendars[0]?.id ?? writableCalendars[0]?.id ?? ""
  const userEmail = identity?.email

  const clearPending = useCallback(() => setPendingDraft(null), [])

  const closeOverlays = useCallback(() => {
    setQuickCreate(null)
    setPopover(null)
    clearPending()
  }, [clearPending])

  const showPendingDraft = useCallback((draft: AgendaEventDraft) => {
    setPendingDraft(draft)
  }, [])

  const openCreateDialog = useCallback(
    (base?: Partial<AgendaEventDraft>, opts?: { keepPending?: boolean }) => {
      setPopover(null)
      setQuickCreate(null)
      if (!opts?.keepPending) clearPending()

      const start = base?.start ?? addHours(startOfHour(new Date()), 1)
      const end = base?.end ?? addMinutes(start, defaultQuickDurationMinutes)
      const draft: AgendaEventDraft = {
        title: "",
        start,
        end,
        allDay: false,
        calendarId: defaultCalendarId,
        ...base,
      }
      showPendingDraft(draft)
      setDialogState({ mode: "create", draft })
    },
    [clearPending, defaultCalendarId, defaultQuickDurationMinutes, showPendingDraft],
  )

  const openEditDialog = useCallback(
    (event: AgendaEvent) => {
      closeOverlays()
      const masterStart = parseICSDate(event.master.start) ?? event.start
      const masterEnd = parseICSDate(event.master.end) ?? event.end
      setDialogState({
        mode: "edit",
        event,
        draft: {
          title: event.title === "(Sans titre)" ? "" : event.title,
          start: masterStart,
          end: masterEnd,
          allDay: event.allDay,
          calendarId: event.calendarId,
          description: event.description,
          location: event.location,
          attendees: event.attendees,
          rrule: event.rrule,
          color: event.master.color,
        },
      })
    },
    [closeOverlays],
  )

  const handledNewParam = useRef(false)
  useEffect(() => {
    if (handledNewParam.current || !route.view) return
    if (searchParams.get("new") !== "1") return
    handledNewParam.current = true
    const guest = searchParams.get("guest")?.trim()
    const guestName = searchParams.get("guest_name")?.trim()
    openCreateDialog({
      title: searchParams.get("title")?.trim() ?? "",
      attendees: guest
        ? [{ email: guest, name: guestName || guest, status: "NEEDS-ACTION" }]
        : [],
    })
    router.replace(buildAgendaPath(view, date))
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [searchParams, route.view])

  useEffect(() => {
    const onKey = (e: KeyboardEvent) => {
      const target = e.target as HTMLElement
      if (
        e.metaKey ||
        e.ctrlKey ||
        e.altKey ||
        target.closest("input, textarea, select, [contenteditable], [role=dialog]")
      )
        return
      switch (e.key.toLowerCase()) {
        case "j":
        case "d":
          navigate("day", date)
          break
        case "s":
        case "w":
          navigate("week", date)
          break
        case "m":
          navigate("month", date)
          break
        case "t":
          navigate(view, new Date())
          break
        case "c":
          openCreateDialog()
          break
        default:
          return
      }
      e.preventDefault()
    }
    window.addEventListener("keydown", onKey)
    return () => window.removeEventListener("keydown", onKey)
  }, [navigate, view, date, openCreateDialog])

  const handleEventClick = useCallback((event: AgendaEvent, anchor: AnchorRect) => {
    setQuickCreate(null)
    clearPending()
    setPopover({ event, anchor })
  }, [clearPending])

  const handleCreateRange = useCallback(
    (start: Date, end: Date, allDay: boolean, anchor: AnchorRect, viaDrag: boolean) => {
      setPopover(null)
      const draft: AgendaEventDraft = {
        title: "",
        start,
        end,
        allDay,
        calendarId: defaultCalendarId,
      }
      showPendingDraft(draft)

      if (viaDrag) {
        openCreateDialog(draft, { keepPending: true })
      } else {
        setDialogState(null)
        setQuickCreate({ start, end, allDay, anchor })
      }
    },
    [defaultCalendarId, openCreateDialog, showPendingDraft],
  )

  const { moveEvent } = useAgendaEventMove()

  const handleEventMove = useCallback(
    (event: AgendaEvent, targetStart: Date) => {
      void moveEvent(event, targetStart)
    },
    [moveEvent],
  )

  const pendingEvent = useMemo(() => {
    if (!pendingDraft) return null
    return draftToPendingEvent(pendingDraft, visibleCalendars.length > 0 ? visibleCalendars : calendars)
  }, [pendingDraft, visibleCalendars, calendars])

  const days = useMemo(
    () => viewDays(view, date, weekStart, weekStartsOn),
    [view, date, weekStart, weekStartsOn],
  )

  return (
    <>
      <AgendaHeader
        view={view}
        date={date}
        weekStart={weekStart}
        weekStartsOn={weekStartsOn}
        onToday={() => navigate(view, new Date())}
        onStep={step}
        onViewChange={(v) => navigate(v, date)}
      />
      <div className="flex min-h-0 flex-1">
        <AgendaSidebar
          selectedDate={date}
          onSelectDate={(d) => navigate(view, d)}
          onCreateEvent={() => openCreateDialog()}
        />
        <main className={cn("flex min-h-0 min-w-0 flex-1 flex-col pb-1 max-sm:pb-0", AGENDA_MAIN_INSET_X)}>
          <div className={AGENDA_CALENDAR_CARD_CLASS} data-agenda-calendar-card>
          {calendarsLoading ? (
            <div className="flex h-full flex-col gap-3 p-6">
              <Skeleton className="h-8 w-64" />
              <Skeleton className="min-h-0 flex-1" />
            </div>
          ) : view === "month" ? (
            <AgendaViewMonth
              date={date}
              weekStart={weekStart}
              weekStartsOn={weekStartsOn}
              events={events}
              pendingEvent={pendingEvent}
              onCreateRange={handleCreateRange}
              onEventClick={handleEventClick}
              onEventMove={handleEventMove}
              onOpenDay={(day) => navigate("day", day)}
            />
          ) : (
            <AgendaViewWeek
              days={days}
              events={events}
              pendingEvent={pendingEvent}
              onCreateRange={handleCreateRange}
              onEventClick={handleEventClick}
              onEventMove={handleEventMove}
              onOpenDay={(day) => navigate("day", day)}
            />
          )}
          </div>
        </main>
      </div>

      <AgendaQuickCreate
        state={quickCreate}
        calendars={writableVisibleCalendars.length > 0 ? writableVisibleCalendars : writableCalendars}
        defaultCalendarId={defaultCalendarId}
        userEmail={userEmail}
        onClose={() => {
          setQuickCreate(null)
          clearPending()
        }}
        onMoreOptions={(draft) => {
          setQuickCreate(null)
          showPendingDraft(draft)
          setDialogState({ mode: "create", draft })
        }}
      />

      <AgendaEventPopover
        state={popover}
        calendars={calendars}
        userEmail={userEmail}
        onClose={() => setPopover(null)}
        onEdit={openEditDialog}
      />

      <AgendaEventDialog
        state={dialogState}
        onClose={() => {
          setDialogState(null)
          clearPending()
        }}
        calendars={writableCalendars}
        userEmail={userEmail}
        onDraftChange={showPendingDraft}
      />
    </>
  )
}
