"use client"

import {
  useEffect,
  useMemo,
  useRef,
  useState,
  type MouseEvent,
  type PointerEvent as ReactPointerEvent,
} from "react"
import { format, isSameDay } from "date-fns"
import { fr } from "date-fns/locale"
import { AgendaEventChip } from "@/components/agenda/agenda-event-chip"
import type { AnchorRect } from "@/components/agenda/agenda-floating-card"
import { formatEventTime, roundToStep } from "@/lib/agenda/agenda-date"
import { readableTextColor } from "@/lib/agenda/agenda-colors"
import { layoutDayEvents } from "@/lib/agenda/agenda-event-layout"
import { eventsOnDay, isMultiDay } from "@/lib/agenda/agenda-events"
import type { AgendaEvent } from "@/lib/agenda/agenda-types"
import { cn } from "@/lib/utils"

const HOUR_PX = 48
const GUTTER_PX = 56
const MIN_EVENT_PX = 22

function anchorFromEvent(e: MouseEvent<HTMLElement>): AnchorRect {
  const rect = e.currentTarget.getBoundingClientRect()
  return { left: rect.left, top: rect.top, width: rect.width, height: rect.height }
}

interface DragState {
  dayIndex: number
  anchorMin: number
  startMin: number
  endMin: number
  moved: boolean
}

export function AgendaViewWeek({
  days,
  events,
  onCreateRange,
  onEventClick,
  onOpenDay,
}: {
  days: Date[]
  events: AgendaEvent[]
  onCreateRange: (start: Date, end: Date, allDay: boolean, anchor: AnchorRect) => void
  onEventClick: (event: AgendaEvent, anchor: AnchorRect) => void
  onOpenDay: (day: Date) => void
}) {
  const scrollRef = useRef<HTMLDivElement>(null)
  const [drag, setDrag] = useState<DragState | null>(null)
  const [now, setNow] = useState(() => new Date())

  useEffect(() => {
    const id = window.setInterval(() => setNow(new Date()), 60_000)
    return () => window.clearInterval(id)
  }, [])

  useEffect(() => {
    const el = scrollRef.current
    if (!el) return
    const target = Math.max(0, (Math.min(now.getHours(), 18) - 1.5) * HOUR_PX)
    el.scrollTop = target
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

  const perDay = useMemo(
    () =>
      days.map((day) => {
        const dayEvents = eventsOnDay(events, day)
        const banners = dayEvents
          .filter((e) => e.allDay || isMultiDay(e))
          .sort((a, b) => a.start.getTime() - b.start.getTime())
        const timed = dayEvents.filter((e) => !e.allDay && !isMultiDay(e))
        return { day, banners, positioned: layoutDayEvents(timed, day) }
      }),
    [days, events],
  )

  const hasBanners = perDay.some((d) => d.banners.length > 0)
  const colTemplate = `${GUTTER_PX}px repeat(${days.length}, minmax(0, 1fr))`

  const minuteFromPointer = (e: ReactPointerEvent<HTMLElement>): number => {
    const rect = e.currentTarget.getBoundingClientRect()
    const minutes = ((e.clientY - rect.top) / HOUR_PX) * 60
    return Math.min(24 * 60, Math.max(0, roundToStep(minutes, 15)))
  }

  const handlePointerDown = (dayIndex: number) => (e: ReactPointerEvent<HTMLDivElement>) => {
    if (e.button !== 0 || (e.target as HTMLElement).closest("[data-agenda-event]")) return
    const min = minuteFromPointer(e)
    e.currentTarget.setPointerCapture(e.pointerId)
    setDrag({ dayIndex, anchorMin: min, startMin: min, endMin: min + 15, moved: false })
  }

  const handlePointerMove = (dayIndex: number) => (e: ReactPointerEvent<HTMLDivElement>) => {
    setDrag((d) => {
      if (!d || d.dayIndex !== dayIndex) return d
      const min = minuteFromPointer(e)
      if (min === d.anchorMin && !d.moved) return d
      return {
        ...d,
        moved: true,
        startMin: Math.min(d.anchorMin, min),
        endMin: Math.max(d.anchorMin, min, Math.min(d.anchorMin, min) + 15),
      }
    })
  }

  const handlePointerUp = (dayIndex: number) => (e: ReactPointerEvent<HTMLDivElement>) => {
    if (!drag || drag.dayIndex !== dayIndex) return
    const day = days[dayIndex]
    const startMin = drag.startMin
    const endMin = drag.moved ? drag.endMin : drag.startMin + 60
    const start = new Date(day)
    start.setHours(0, startMin, 0, 0)
    const end = new Date(day)
    end.setHours(0, Math.max(endMin, startMin + 15), 0, 0)

    const colRect = e.currentTarget.getBoundingClientRect()
    const anchor: AnchorRect = {
      left: colRect.left,
      top: colRect.top + (startMin / 60) * HOUR_PX,
      width: colRect.width,
      height: Math.max(((endMin - startMin) / 60) * HOUR_PX, MIN_EVENT_PX),
    }
    setDrag(null)
    onCreateRange(start, end, false, anchor)
  }

  return (
    <div className="flex h-full min-h-0 flex-col overflow-hidden rounded-tl-2xl border-t border-l border-border/60 bg-card">
      {/* En-tête : jours + rangée journée entière */}
      <div className="shrink-0 border-b border-border/60 pr-[var(--agenda-sbw,0px)]">
        <div className="grid" style={{ gridTemplateColumns: colTemplate }}>
          <div />
          {days.map((day) => {
            const isToday = isSameDay(day, now)
            return (
              <div
                key={day.getTime()}
                className="flex flex-col items-center gap-0.5 border-l border-border/40 pt-2 pb-1"
              >
                <span className="text-[0.7rem] font-medium tracking-wide text-muted-foreground uppercase">
                  {format(day, "EEE", { locale: fr }).replace(".", "")}
                </span>
                <button
                  type="button"
                  onClick={() => onOpenDay(day)}
                  className={cn(
                    "flex size-10 items-center justify-center rounded-full text-[1.45rem] font-normal text-foreground/80 hover:bg-mail-nav-hover",
                    isToday &&
                      "bg-primary font-medium text-primary-foreground hover:bg-primary",
                  )}
                >
                  {day.getDate()}
                </button>
              </div>
            )
          })}
        </div>
        {hasBanners && (
          <div className="grid" style={{ gridTemplateColumns: colTemplate }}>
            <div className="pt-0.5 pr-2 text-right text-[0.65rem] text-muted-foreground" />
            {perDay.map(({ day, banners }) => (
              <div
                key={day.getTime()}
                className="flex min-h-6 flex-col gap-0.5 border-l border-border/40 px-0.5 pb-1"
              >
                {banners.map((event) => (
                  <AgendaEventChip
                    key={event.key}
                    event={event}
                    filled
                    onClick={(e) => {
                      e.stopPropagation()
                      onEventClick(event, anchorFromEvent(e))
                    }}
                  />
                ))}
              </div>
            ))}
          </div>
        )}
      </div>

      {/* Grille horaire */}
      <div ref={scrollRef} className="min-h-0 flex-1 overflow-y-auto">
        <div
          className="relative grid"
          style={{ gridTemplateColumns: colTemplate, height: 24 * HOUR_PX }}
        >
          {/* Gouttière heures */}
          <div className="relative">
            {Array.from({ length: 23 }, (_, i) => i + 1).map((h) => (
              <span
                key={h}
                className="absolute right-2 -translate-y-1/2 text-[0.65rem] text-muted-foreground"
                style={{ top: h * HOUR_PX }}
              >
                {String(h).padStart(2, "0")}:00
              </span>
            ))}
          </div>

          {perDay.map(({ day, positioned }, dayIndex) => {
            const isToday = isSameDay(day, now)
            const nowTop = (now.getHours() * 60 + now.getMinutes()) * (HOUR_PX / 60)
            return (
              <div
                key={day.getTime()}
                className="relative cursor-pointer touch-none border-l border-border/40"
                onPointerDown={handlePointerDown(dayIndex)}
                onPointerMove={handlePointerMove(dayIndex)}
                onPointerUp={handlePointerUp(dayIndex)}
              >
                {/* Lignes d'heures */}
                {Array.from({ length: 23 }, (_, i) => i + 1).map((h) => (
                  <div
                    key={h}
                    aria-hidden
                    className="absolute right-0 left-0 border-t border-border/40"
                    style={{ top: h * HOUR_PX }}
                  />
                ))}

                {/* Sélection en cours */}
                {drag && drag.dayIndex === dayIndex && drag.moved && (
                  <div
                    aria-hidden
                    className="absolute right-1 left-0.5 z-10 rounded-md bg-primary/25 ring-1 ring-primary/50"
                    style={{
                      top: (drag.startMin / 60) * HOUR_PX,
                      height: Math.max(
                        ((drag.endMin - drag.startMin) / 60) * HOUR_PX,
                        8,
                      ),
                    }}
                  >
                    <span className="px-1.5 text-[0.65rem] font-medium text-primary">
                      {formatMinutes(drag.startMin)} – {formatMinutes(drag.endMin)}
                    </span>
                  </div>
                )}

                {/* Événements positionnés */}
                {positioned.map(({ event, top, duration, leftPct, widthPct }) => {
                  const compact = (duration / 60) * HOUR_PX < 40
                  return (
                    <button
                      key={event.key}
                      type="button"
                      data-agenda-event
                      className="absolute z-20 flex flex-col overflow-hidden rounded-md px-1.5 py-0.5 text-left shadow-sm ring-1 ring-black/5 transition-[filter] hover:z-30 hover:brightness-95 dark:ring-white/10 dark:hover:brightness-110"
                      style={{
                        top: (top / 60) * HOUR_PX,
                        height: Math.max((duration / 60) * HOUR_PX - 2, MIN_EVENT_PX),
                        left: `calc(${leftPct}% + 1px)`,
                        width: `calc(${widthPct}% - 3px)`,
                        backgroundColor: event.color,
                        color: readableTextColor(event.color),
                      }}
                      onClick={(e) => {
                        e.stopPropagation()
                        onEventClick(event, anchorFromEvent(e))
                      }}
                      onPointerDown={(e) => e.stopPropagation()}
                    >
                      <span
                        className={cn(
                          "truncate text-xs leading-tight font-medium",
                          compact && "text-[0.7rem]",
                        )}
                      >
                        {event.title}
                        {compact && (
                          <span className="font-normal opacity-90">
                            {" "}
                            ⋅ {formatEventTime(event.start)}
                          </span>
                        )}
                      </span>
                      {!compact && (
                        <span className="truncate text-[0.7rem] leading-tight opacity-90">
                          {formatEventTime(event.start)} – {formatEventTime(event.end)}
                        </span>
                      )}
                    </button>
                  )
                })}

                {/* Indicateur maintenant */}
                {isToday && (
                  <div
                    aria-hidden
                    className="pointer-events-none absolute right-0 left-0 z-30"
                    style={{ top: nowTop }}
                  >
                    <div className="relative h-0.5 bg-red-500">
                      <span className="absolute top-1/2 -left-1 size-3 -translate-y-1/2 rounded-full bg-red-500" />
                    </div>
                  </div>
                )}
              </div>
            )
          })}
        </div>
      </div>
    </div>
  )
}

function formatMinutes(min: number): string {
  const h = Math.floor(min / 60)
  const m = min % 60
  return `${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}`
}
