"use client";

import { useMemo, useState } from "react";
import type { CalendarEvent, CalendarSource } from "@/types/dashboard";

type CalendarWidgetProps = {
  widgetId: string;
  editMode: boolean;
  events: CalendarEvent[];
  error: string | null;
  sources: CalendarSource[];
  selectedSourceIds: string[];
  nextEventsCount: number;
  onToggleSource: (widgetId: string, sourceId: string) => void;
  onChangeEventsCount: (widgetId: string, count: number) => void;
};

type CalendarDay = {
  key: string;
  date: Date;
  inCurrentMonth: boolean;
  isToday: boolean;
  events: CalendarEvent[];
};

const weekdayLabels = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"];

function dateKey(date: Date): string {
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, "0");
  const day = String(date.getDate()).padStart(2, "0");

  return `${year}-${month}-${day}`;
}

function formatEventDate(value: string): string {
  return new Intl.DateTimeFormat("de-DE", {
    weekday: "short",
    day: "2-digit",
    month: "2-digit",
    hour: "2-digit",
    minute: "2-digit"
  }).format(new Date(value));
}

function formatEventTime(value: string): string {
  return new Intl.DateTimeFormat("de-DE", {
    hour: "2-digit",
    minute: "2-digit"
  }).format(new Date(value));
}

function formatMonthLabel(value: Date): string {
  return new Intl.DateTimeFormat("de-DE", {
    month: "long",
    year: "numeric"
  }).format(value);
}

function buildCalendarDays(monthDate: Date, eventsByDate: Map<string, CalendarEvent[]>): CalendarDay[] {
  const year = monthDate.getFullYear();
  const month = monthDate.getMonth();
  const firstDayOfMonth = new Date(year, month, 1);
  const mondayBasedStartOffset = (firstDayOfMonth.getDay() + 6) % 7;

  const gridStart = new Date(firstDayOfMonth);
  gridStart.setDate(firstDayOfMonth.getDate() - mondayBasedStartOffset);
  gridStart.setHours(0, 0, 0, 0);

  const today = dateKey(new Date());
  const days: CalendarDay[] = [];

  for (let index = 0; index < 42; index += 1) {
    const date = new Date(gridStart);
    date.setDate(gridStart.getDate() + index);

    const key = dateKey(date);

    days.push({
      key,
      date,
      inCurrentMonth: date.getMonth() === month,
      isToday: key === today,
      events: eventsByDate.get(key) ?? []
    });
  }

  return days;
}

function groupEventsByDate(events: CalendarEvent[]): Map<string, CalendarEvent[]> {
  const grouped = new Map<string, CalendarEvent[]>();

  events.forEach((event) => {
    const key = dateKey(new Date(event.start));
    const existing = grouped.get(key) ?? [];

    grouped.set(key, [...existing, event]);
  });

  return grouped;
}

export default function CalendarWidget({
  widgetId,
  editMode,
  events,
  error,
  sources,
  selectedSourceIds,
  nextEventsCount,
  onToggleSource,
  onChangeEventsCount
}: CalendarWidgetProps) {
  const [calendarMonth, setCalendarMonth] = useState(() => new Date());

  const eventsByDate = useMemo(() => groupEventsByDate(events), [events]);
  const calendarDays = useMemo(() => buildCalendarDays(calendarMonth, eventsByDate), [calendarMonth, eventsByDate]);
  const clampedEventsCount = Math.max(0, Math.min(10, nextEventsCount));
  const nextEvents = useMemo(
    () =>
      [...events]
        .sort((a, b) => new Date(a.start).getTime() - new Date(b.start).getTime())
        .slice(0, clampedEventsCount),
    [events, clampedEventsCount]
  );

  return (
    <>
      {editMode ? (
        <details className="calendarSourcePanel widgetNoDrag">
          <summary>Kalenderauswahl</summary>

          <div className="calendarSourceForm">
            {sources.length === 0 ? (
              <p className="muted">
                Keine Kalenderquellen angelegt. Lege Kalender in den Benutzereinstellungen an.
              </p>
            ) : null}

            {sources.map((source) => (
              <label className="calendarSourceCheckbox" key={source.id}>
                <input
                  type="checkbox"
                  checked={selectedSourceIds.includes(source.id)}
                  onChange={() => onToggleSource(widgetId, source.id)}
                />
                <span className="calendarSourceColorDot" style={{ background: source.color }} />
                <span>
                  <strong>{source.name}</strong>
                  <small>{source.type === "EXCHANGE_EWS" ? "Exchange" : "ICS"}</small>
                </span>
              </label>
            ))}

            <label className="fieldLabel">
              Termine unter dem Kalender
              <select
                className="select"
                value={nextEventsCount}
                onChange={(event) => onChangeEventsCount(widgetId, Number(event.target.value))}
              >
                <option value={0}>Ausblenden</option>
                {[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((n) => (
                  <option key={n} value={n}>{n} {n === 1 ? "Termin" : "Termine"}</option>
                ))}
              </select>
            </label>
          </div>
        </details>
      ) : null}

      <div className="calendarHeader widgetNoDrag">
        <button type="button" className="calendarNavButton" onClick={() => setCalendarMonth((c) => new Date(c.getFullYear(), c.getMonth() - 1, 1))}>
          Zurück
        </button>

        <button type="button" className="calendarMonthButton" onClick={() => setCalendarMonth(new Date())}>
          {formatMonthLabel(calendarMonth)}
        </button>

        <button type="button" className="calendarNavButton" onClick={() => setCalendarMonth((c) => new Date(c.getFullYear(), c.getMonth() + 1, 1))}>
          Weiter
        </button>
      </div>

      {selectedSourceIds.length === 0 ? <p className="muted calendarStatus">Keine Kalenderquelle ausgewählt.</p> : null}

      <div className="calendarWeekdays">
        {weekdayLabels.map((label) => (
          <div className="calendarWeekday" key={label}>{label}</div>
        ))}
      </div>

      <div className="calendarGrid">
        {calendarDays.map((day) => (
          <div
            className={[
              "calendarDay",
              day.inCurrentMonth ? "" : "calendarDayMuted",
              day.isToday ? "calendarDayToday" : "",
              day.events.length > 0 ? "calendarDayWithEvents" : ""
            ]
              .filter(Boolean)
              .join(" ")}
            key={day.key}
          >
            <span className="calendarDayNumber">{day.date.getDate()}</span>

            {day.events.length > 0 ? <span className="calendarEventCount">{day.events.length}</span> : null}

            {day.events.length > 0 ? (
              <div className="calendarTooltip">
                {day.events.slice(0, 5).map((event) => (
                  <div className="calendarTooltipItem" key={event.id}>
                    <span className="calendarTooltipTime">{formatEventTime(event.start)}</span>
                    <span>{event.title}</span>
                  </div>
                ))}

                {day.events.length > 5 ? <div className="calendarTooltipMore">Weitere Termine vorhanden</div> : null}
              </div>
            ) : null}
          </div>
        ))}
      </div>

      {error ? <p className="muted calendarStatus">{error}</p> : null}

      {clampedEventsCount > 0 ? (
        <section className="nextEventsBlock">
          <h3>Nächste Termine</h3>

          {nextEvents.length === 0 ? <p className="muted">Keine nächsten Termine.</p> : null}

          <div className="eventList">
            {nextEvents.map((event) => (
              <article className="eventItem" key={event.id}>
                <div className="eventDate">{formatEventDate(event.start)}</div>
                <div className="eventTitle">{event.title}</div>
                {event.location ? <div className="eventLocation">{event.location}</div> : null}
              </article>
            ))}
          </div>
        </section>
      ) : null}
    </>
  );
}
