"use client";

import { useMemo, useState, useCallback, type DragEvent } from "react";
import { useTranslations } from "next-intl";
import { format, parseISO } from "date-fns";
import { cn } from "@/lib/utils";
import { EventCard } from "./event-card";
import { buildWeekSegments, getEventDayBounds, getPrimaryCalendarId } from "@/lib/calendar-utils";
import type { CalendarEvent, Calendar } from "@/lib/jmap/types";
import { useAuthStore } from "@/stores/auth-store";
import { useCalendarStore } from "@/stores/calendar-store";
import { useSettingsStore } from "@/stores/settings-store";
import type { PendingEventPreview } from "./event-modal";
import { toast } from "@/stores/toast-store";
import { useCalendarLocale } from "@/hooks/use-calendar-locale";
import { RadialMenu, type RadialMenuItem } from "@/components/ui/radial-menu";
import { Pencil, Trash2, Copy } from "lucide-react";

interface CalendarMonthViewProps {
  selectedDate: Date;
  events: CalendarEvent[];
  calendars: Calendar[];
  onSelectDate: (date: Date) => void;
  onSelectEvent: (event: CalendarEvent, anchorRect: DOMRect) => void;
  onHoverEvent?: (event: CalendarEvent, anchorRect: DOMRect) => void;
  onHoverLeave?: () => void;
  onContextMenuEvent?: (e: React.MouseEvent, event: CalendarEvent) => void;
  onContextMenuEmpty?: (e: React.MouseEvent, date: Date, hour?: number, allDayArea?: boolean) => void;
  onCreateAtTime?: (date: Date) => void;
  onEditEvent?: (event: CalendarEvent) => void;
  onDeleteEvent?: (event: CalendarEvent) => void;
  onDuplicateEvent?: (event: CalendarEvent) => void;
  firstDayOfWeek?: number;
  isMobile?: boolean;
  pendingPreview?: PendingEventPreview | null;
}

export function CalendarMonthView({
  selectedDate,
  events,
  calendars,
  onSelectDate,
  onSelectEvent,
  onHoverEvent,
  onHoverLeave,
  onContextMenuEvent,
  onContextMenuEmpty,
  onCreateAtTime,
  onEditEvent,
  onDeleteEvent,
  onDuplicateEvent,
  firstDayOfWeek = 1,
  isMobile,
  pendingPreview,
}: CalendarMonthViewProps) {
  const t = useTranslations("calendar");
  const showTimeInMonthView = useSettingsStore((state) => state.showTimeInMonthView);
  // On mobile the month view collapses events to dots unless the user opted
  // into full entries via "Show time in month view" (#666).
  const showChips = !isMobile || showTimeInMonthView;
  const overlayTop = isMobile ? 34 : 30;
  const rowHeight = isMobile ? 18 : 22;
  const chipHeight = rowHeight - 2;
  const {
    weekStartsOn,
    dayHeaderKeys,
    getMonthGridDays,
    checkIsToday,
    checkIsSameMonth,
    checkIsSameDay,
    formatDayNumber,
    formatFullDate,
  } = useCalendarLocale();

  const days = useMemo(
    () => getMonthGridDays(selectedDate),
    [selectedDate, getMonthGridDays],
  );

  const calendarMap = useMemo(() => {
    const map = new Map<string, Calendar>();
    calendars.forEach((c) => map.set(c.id, c));
    return map;
  }, [calendars]);

  const eventsByDate = useMemo(() => {
    const map = new Map<string, CalendarEvent[]>();
    events.forEach((e) => {
      try {
        const { startDay, endDay } = getEventDayBounds(e);

        const cursor = new Date(startDay);
        while (cursor <= endDay) {
          const key = format(cursor, "yyyy-MM-dd");
          const arr = map.get(key) || [];
          arr.push(e);
          map.set(key, arr);
          cursor.setDate(cursor.getDate() + 1);
        }
      } catch { /* skip invalid dates */ }
    });
    return map;
  }, [events]);

  const weeks = useMemo(() => {
    const result: Date[][] = [];
    for (let i = 0; i < days.length; i += 7) {
      result.push(days.slice(i, i + 7));
    }
    return result;
  }, [days]);

  const weekSegments = useMemo(() => {
    return weeks.map((week) => {
      const segments = buildWeekSegments(events, week);
      const rowCount = segments.reduce((maxRows, segment) => Math.max(maxRows, segment.row + 1), 0);
      return { week, segments, rowCount };
    });
  }, [events, weeks]);

  const [dropDayKey, setDropDayKey] = useState<string | null>(null);

  // Radial menu state
  const [radialMenuOpen, setRadialMenuOpen] = useState(false);
  const [radialMenuPos, setRadialMenuPos] = useState({ x: 0, y: 0 });
  const [radialMenuEvent, setRadialMenuEvent] = useState<CalendarEvent | null>(null);

  const closeRadialMenu = useCallback(() => {
    setRadialMenuOpen(false);
  }, []);

  const radialMenuItems = useMemo<RadialMenuItem[]>(() => {
    if (!radialMenuEvent) return [];
    const ev = radialMenuEvent;
    const items: RadialMenuItem[] = [];
    if (onEditEvent) {
      items.push({
        id: "edit",
        icon: <Pencil className="w-5 h-5" />,
        label: t("edit"),
        onClick: () => { onEditEvent(ev); },
      });
    }
    if (onDeleteEvent) {
      items.push({
        id: "delete",
        icon: <Trash2 className="w-5 h-5" />,
        label: t("delete"),
        onClick: () => { onDeleteEvent(ev); },
        destructive: true,
      });
    }
    if (onDuplicateEvent) {
      items.push({
        id: "duplicate",
        icon: <Copy className="w-5 h-5" />,
        label: t("duplicate"),
        onClick: () => { onDuplicateEvent(ev); },
      });
    }
    return items;
  }, [radialMenuEvent, t, onEditEvent, onDeleteEvent, onDuplicateEvent]);

  const handleRadialMenuEvent = useCallback((e: React.MouseEvent, event: CalendarEvent) => {
    setRadialMenuPos({ x: e.clientX, y: e.clientY });
    setRadialMenuEvent(event);
    setRadialMenuOpen(true);
    onContextMenuEvent?.(e, event);
  }, [onContextMenuEvent]);

  const handleCellDragOver = useCallback((e: DragEvent<HTMLDivElement>, dayKey: string) => {
    if (!e.dataTransfer.types.includes("application/x-calendar-event")) return;
    e.preventDefault();
    e.dataTransfer.dropEffect = "move";
    setDropDayKey((prev) => prev === dayKey ? prev : dayKey);
  }, []);

  const handleCellDragLeave = useCallback((e: DragEvent<HTMLDivElement>) => {
    const related = e.relatedTarget as Node | null;
    if (!e.currentTarget.contains(related)) setDropDayKey(null);
  }, []);

  const handleCellDrop = useCallback(async (e: DragEvent<HTMLDivElement>, day: Date) => {
    e.preventDefault();
    setDropDayKey(null);
    const json = e.dataTransfer.getData("application/x-calendar-event");
    if (!json) return;
    try {
      const data = JSON.parse(json);
      const originalStart = parseISO(data.originalStart);
      const event = useCalendarStore.getState().events.find(e => e.id === data.eventId);
      const isAllDay = event?.showWithoutTime;
      const newStart = new Date(day);
      newStart.setHours(originalStart.getHours(), originalStart.getMinutes(), originalStart.getSeconds(), 0);
      const newStartISO = isAllDay ? format(newStart, "yyyy-MM-dd") : format(newStart, "yyyy-MM-dd'T'HH:mm:ss");
      if (newStartISO === data.originalStart) return;
      const client = useAuthStore.getState().client;
      if (!client) return;
      const hasParticipants = event?.participants && Object.keys(event.participants).length > 0;
      await useCalendarStore.getState().updateEvent(client, data.eventId, { start: newStartISO }, hasParticipants || undefined);
    } catch {
      toast.error(t("notifications.event_move_error"));
    }
  }, [t]);

  return (
    <div className="flex flex-col flex-1 overflow-hidden" role="grid" aria-label={formatFullDate(selectedDate)}>
      <div className="grid grid-cols-7 border-b border-border" role="row">
        {dayHeaderKeys.map((d) => (
          <div key={d} role="columnheader" className={cn(
            "text-center text-xs font-medium text-muted-foreground py-2 border-e border-border last:border-e-0",
            isMobile && "py-1.5 text-[11px]"
          )}>
            {isMobile ? t(`days.${d}`).slice(0, 2) : t(`days.${d}`)}
          </div>
        ))}
      </div>

      <div className="flex-1 flex flex-col overflow-y-auto">
        {weekSegments.map(({ week, segments, rowCount }, wi) => (
          <div key={wi} className={cn(
            "relative flex-1 border-b border-border last:border-b-0",
            isMobile ? "min-h-[52px]" : "min-h-[100px]"
          )} role="row" style={showChips ? { minHeight: Math.max(isMobile ? 52 : 100, overlayTop + 4 + rowCount * rowHeight + 8) } : undefined}>
            <div className="grid grid-cols-7 h-full">
            {week.map((day) => {
              const inMonth = checkIsSameMonth(day, selectedDate);
              const selected = checkIsSameDay(day, selectedDate);
              const today = checkIsToday(day);
              const key = format(day, "yyyy-MM-dd");
              const dayEvents = eventsByDate.get(key) || [];
              const fullDateLabel = formatFullDate(day);

              return (
                <div
                  key={key}
                  role="gridcell"
                  aria-selected={selected}
                  aria-label={fullDateLabel}
                  onClick={() => onSelectDate(day)}
                  onDoubleClick={() => onCreateAtTime?.(day)}
                  onContextMenu={onContextMenuEmpty ? (e) => onContextMenuEmpty(e, day, undefined, true) : undefined}
                  onDragOver={(e) => handleCellDragOver(e, key)}
                  onDragLeave={handleCellDragLeave}
                  onDrop={(e) => handleCellDrop(e, day)}
                  className={cn(
                    "border-e border-border last:border-e-0 p-1 cursor-pointer transition-colors touch-manipulation",
                    !inMonth && "bg-muted/30",
                    "hover:bg-muted/50",
                    selected && isMobile && "bg-primary/10",
                    dropDayKey === key && "ring-2 ring-inset ring-primary bg-primary/10"
                  )}
                >
                  <div className="flex items-center justify-center mb-0.5">
                    <span
                      className={cn(
                        "inline-flex items-center justify-center rounded-full",
                        isMobile ? "w-7 h-7 text-xs" : "w-6 h-6 text-xs",
                        today && !selected && "bg-primary text-primary-foreground font-bold",
                        selected && "bg-primary text-primary-foreground font-bold",
                        !inMonth && !selected && !today && "text-muted-foreground/50",
                        inMonth && !selected && !today && "font-medium"
                      )}
                    >
                      {formatDayNumber(day)}
                    </span>
                  </div>
                  {isMobile && !showChips ? (
                    <div className="flex items-center justify-center gap-0.5 flex-wrap">
                      {dayEvents.slice(0, 3).map((ev) => {
                        const calId = getPrimaryCalendarId(ev);
                        const cal = calId ? calendarMap.get(calId) : undefined;
                        const evColor = ev.color || cal?.color || "#3b82f6";
                        return (
                          <span
                            key={ev.id}
                            className="w-1.5 h-1.5 rounded-full"
                            style={{ backgroundColor: evColor }}
                          />
                        );
                      })}
                      {dayEvents.length > 3 && (
                        <span className="w-1.5 h-1.5 rounded-full bg-muted-foreground/40" />
                      )}
                      {pendingPreview && checkIsSameDay(pendingPreview.start, day) && (
                        <span
                          className="w-1.5 h-1.5 rounded-full border border-dashed"
                          style={{ borderColor: calendarMap.get(pendingPreview.calendarId)?.color || "#3b82f6" }}
                        />
                      )}
                    </div>
                  ) : null}
                </div>
              );
            })}
            </div>

            {showChips && pendingPreview && (() => {
              const previewDayIdx = week.findIndex(d => checkIsSameDay(d, pendingPreview.start));
              if (previewDayIdx === -1) return null;
              const previewRow = rowCount;
              const cal = calendarMap.get(pendingPreview.calendarId);
              const color = cal?.color || "#3b82f6";
              return (
                <div className="absolute inset-x-0 pointer-events-none" style={{ top: overlayTop }}>
                  <div
                    className="absolute px-0.5"
                    style={{
                      left: `calc(${(previewDayIdx / 7) * 100}% + 1px)`,
                      width: `calc(${(1 / 7) * 100}% - 2px)`,
                      top: previewRow * rowHeight,
                      height: chipHeight,
                    }}
                  >
                    <div
                      className={cn(
                        "h-full rounded text-[10px] font-medium truncate border-2 border-dashed",
                        isMobile ? "leading-[16px] px-1" : "leading-[20px] px-1.5"
                      )}
                      style={{ borderColor: color, color, backgroundColor: `${color}10` }}
                    >
                      {pendingPreview.title}
                    </div>
                  </div>
                </div>
              );
            })()}

            {showChips && segments.length > 0 && (
              <div className="absolute inset-x-0 pointer-events-none" style={{ top: overlayTop }}>
                {segments.map((segment) => {
                  const calId = getPrimaryCalendarId(segment.event);
                  return (
                    <div
                      key={`${segment.event.id}-${segment.startIndex}-${segment.row}`}
                      className="absolute px-0.5 pointer-events-auto"
                      style={{
                        left: `calc(${(segment.startIndex / 7) * 100}% + 1px)`,
                        width: `calc(${(segment.span / 7) * 100}% - 2px)`,
                        top: segment.row * rowHeight,
                        height: chipHeight,
                      }}
                    >
                      <EventCard
                        event={segment.event}
                        calendar={calId ? calendarMap.get(calId) : undefined}
                        variant="span"
                        continuesBefore={segment.continuesBefore}
                        continuesAfter={segment.continuesAfter}
                        onClick={(rect) => onSelectEvent(segment.event, rect)}
                        onMouseEnter={(rect) => onHoverEvent?.(segment.event, rect)}
                        onMouseLeave={onHoverLeave}
                        onContextMenu={handleRadialMenuEvent}
                        draggable
                        className={isMobile ? "text-[10px] px-1" : undefined}
                      />
                    </div>
                  );
                })}
              </div>
            )}
          </div>
        ))}
      </div>

      <RadialMenu
        items={radialMenuItems}
        isOpen={radialMenuOpen}
        position={radialMenuPos}
        onClose={closeRadialMenu}
      />
    </div>
  );
}
