import React, { useEffect, useMemo, useState } from 'react';
import {
  ScheduleComponent,
  Day,
  Week,
  WorkWeek,
  Month,
  Agenda,
  Inject,
  ViewsDirective,
  ViewDirective,
} from '@syncfusion/ej2-react-schedule';
import { DropDownListComponent } from '@syncfusion/ej2-react-dropdowns';
import { L10n, loadCldr, setCulture } from '@syncfusion/ej2-base';
import type {
  EventRenderedArgs,
  ActionEventArgs,
  RenderCellEventArgs,
} from '@syncfusion/ej2-react-schedule';
import { fetchEvents } from './apiEvents';
import { fetchGroups } from './apiGroups';
import { getGroupColor } from './groupColors';
import { deleteEvent } from './apiEvents';
import CustomEventModal from './components/CustomEventModal';
import { fetchMediaById } from './apiClients';
import { listHolidays, type Holiday } from './apiHolidays';
import {
  getAcademicPeriodForDate,
  listAcademicPeriods,
  setActiveAcademicPeriod,
} from './apiAcademicPeriods';
import {
  Presentation,
  Globe,
  Video,
  MessageSquare,
  School,
  CheckCircle,
  AlertCircle,
  TentTree,
} from 'lucide-react';
import caGregorian from './cldr/ca-gregorian.json';
import numbers from './cldr/numbers.json';
import timeZoneNames from './cldr/timeZoneNames.json';
import numberingSystems from './cldr/numberingSystems.json';

// Typ für Gruppe ergänzen
type Group = {
  id: string;
  name: string;
};

// Typ für Event ergänzen
type Event = {
  Id: string;
  Subject: string;
  StartTime: Date;
  EndTime: Date;
  IsAllDay: boolean;
  IsBlock?: boolean; // Syncfusion block appointment
  isHoliday?: boolean; // marker for styling/logic
  MediaId?: string | number;
  SlideshowInterval?: number;
  WebsiteUrl?: string;
  Icon?: string; // <--- Icon ergänzen!
  Type?: string; // <--- Typ ergänzen, falls benötigt
  OccurrenceOfId?: string; // Serieninstanz
  Recurrence?: boolean; // Marker für Serientermin
  RecurrenceRule?: string | null;
  RecurrenceEnd?: string | null;
  SkipHolidays?: boolean;
  RecurrenceException?: string;
};

type RawEvent = {
  Id: string;
  Subject: string;
  StartTime: string;
  EndTime: string;
  IsAllDay: boolean;
  MediaId?: string | number;
  Icon?: string; // <--- Icon ergänzen!
  Type?: string;
  OccurrenceOfId?: string;
  RecurrenceRule?: string | null;
  RecurrenceEnd?: string | null;
  SkipHolidays?: boolean;
  RecurrenceException?: string;
};

// CLDR-Daten laden (direkt die JSON-Objekte übergeben)
loadCldr(
  caGregorian as object,
  numbers as object,
  timeZoneNames as object,
  numberingSystems as object
);

// Deutsche Lokalisierung für den Scheduler
L10n.load({
  de: {
    schedule: {
      day: 'Tag',
      week: 'Woche',
      workWeek: 'Arbeitswoche',
      month: 'Monat',
      agenda: 'Agenda',
      today: 'Heute',
      noEvents: 'Keine Termine',
      allDay: 'Ganztägig',
      start: 'Start',
      end: 'Ende',
      event: 'Termin',
      save: 'Speichern',
      cancel: 'Abbrechen',
      delete: 'Löschen',
      edit: 'Bearbeiten',
      newEvent: 'Neuer Termin',
      title: 'Titel',
      description: 'Beschreibung',
      location: 'Ort',
      recurrence: 'Wiederholung',
      repeat: 'Wiederholen',
      deleteEvent: 'Termin löschen',
      deleteContent: 'Möchten Sie diesen Termin wirklich löschen?',
      moreDetails: 'Mehr Details',
      addTitle: 'Termintitel',
    },
  },
});

// Kultur setzen
setCulture('de');

// Mapping für Lucide-Icons
const iconMap: Record<string, React.ElementType> = {
  Presentation,
  Globe,
  Video,
  MessageSquare,
  School,
};

const eventTemplate = (event: Event) => {
  const IconComponent = iconMap[event.Icon ?? ''] || null;
  // Zeitangabe formatieren
  const start = event.StartTime instanceof Date ? event.StartTime : new Date(event.StartTime);
  const end = event.EndTime instanceof Date ? event.EndTime : new Date(event.EndTime);
  const timeString = `${start.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })} - ${end.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}`;

  // Render TentTree icon if SkipHolidays is true
  const showTentTree = !!event.SkipHolidays;
  return (
    <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start' }}>
      <div style={{ display: 'flex', alignItems: 'center', color: '#000', marginBottom: 2 }}>
        {IconComponent && (
          <span style={{ verticalAlign: 'middle', display: 'inline-block', marginRight: 6 }}>
            <IconComponent size={18} color="#000" />
          </span>
        )}
        {showTentTree && (
          <span
            style={{ verticalAlign: 'middle', display: 'inline-block', marginRight: 6 }}
            title="Ferientage werden berücksichtigt"
          >
            <TentTree size={16} color="#000" />
          </span>
        )}
        <span style={{ marginTop: 3 }}>{event.Subject}</span>
      </div>
      <div style={{ fontSize: '0.95em', color: '#000', marginTop: -2 }}>{timeString}</div>
    </div>
  );
}

// Robust ISO date parsing: append 'Z' only if no timezone offset present
function parseEventDate(iso: string): Date {
  if (!iso) return new Date(NaN);
  // If string already contains 'Z' or a timezone offset like +00:00/-02:00, don't modify
  const hasTZ = /Z$/i.test(iso) || /[+-]\d{2}:\d{2}$/.test(iso);
  const s = hasTZ ? iso : `${iso}Z`;
  return new Date(s);
}

const Appointments: React.FC = () => {

  // Debug logging removed
    const [groups, setGroups] = useState<Group[]>([]);
    const [selectedGroupId, setSelectedGroupId] = useState<string | null>(null);
    const [events, setEvents] = useState<Event[]>([]);
  const [holidays, setHolidays] = useState<Holiday[]>([]);
  const [modalOpen, setModalOpen] = useState(false);
  const [modalInitialData, setModalInitialData] = useState({});
  const [schedulerKey, setSchedulerKey] = useState(0);
  const [editMode, setEditMode] = useState(false); // NEU: Editiermodus
  const [showInactive, setShowInactive] = React.useState(true);
  const [allowScheduleOnHolidays, setAllowScheduleOnHolidays] = React.useState(false);
  const [showHolidayList, setShowHolidayList] = React.useState(true);
  // Always let Syncfusion handle recurrence; do not expand on backend
  // Remove expandRecurrences toggle and state
  const scheduleRef = React.useRef<ScheduleComponent | null>(null);
  const [holidaysInView, setHolidaysInView] = React.useState<number>(0);
  const [schoolYearLabel, setSchoolYearLabel] = React.useState<string>('');
  const [hasSchoolYearPlan, setHasSchoolYearPlan] = React.useState<boolean>(false);
  const [periods, setPeriods] = React.useState<{ id: number; label: string }[]>([]);
  const [activePeriodId, setActivePeriodId] = React.useState<number | null>(null);

  // Gruppen laden
  useEffect(() => {
    fetchGroups()
      .then(data => {
        // Nur Gruppen mit id != 1 berücksichtigen (nicht zugeordnet ignorieren)
        const filtered = Array.isArray(data) ? data.filter(g => g.id && g.name && g.id !== 1) : [];
        setGroups(filtered);
        if (filtered.length > 0) setSelectedGroupId(filtered[0].id);
      })
      .catch(console.error);
  }, []);

  // Holidays laden
  useEffect(() => {
    listHolidays()
      .then(res => setHolidays(res.holidays || []))
      .catch(err => console.error('Ferien laden fehlgeschlagen:', err));
  }, []);

  // Perioden laden (Dropdown)
  useEffect(() => {
    listAcademicPeriods()
      .then(all => {
        setPeriods(all.map(p => ({ id: p.id, label: p.display_name || p.name })));
        const active = all.find(p => p.is_active);
        setActivePeriodId(active ? active.id : null);
      })
      .catch(err => console.error('Akademische Perioden laden fehlgeschlagen:', err));
  }, []);

  // fetchAndSetEvents als useCallback definieren, damit die Dependency korrekt ist:
  const fetchAndSetEvents = React.useCallback(async () => {
    if (!selectedGroupId) {
      setEvents([]);
      return;
    }
    try {
      // Sichtbaren Bereich bestimmen (optional, for future filtering)
      const inst = scheduleRef.current;
      let startRange: Date | undefined;
      let endRange: Date | undefined;
      // Fallback to current week if scheduler is not initialized yet
      const today = new Date();
      const fallbackStart = new Date(today);
      const day = today.getDay();
      const diffToMonday = (day + 6) % 7; // Monday=0
      fallbackStart.setDate(today.getDate() - diffToMonday);
      fallbackStart.setHours(0, 0, 0, 0);
      const fallbackEnd = new Date(fallbackStart);
      fallbackEnd.setDate(fallbackStart.getDate() + 6);
      fallbackEnd.setHours(23, 59, 59, 999);
      if (inst) {
        const view = inst.currentView as 'Day' | 'Week' | 'WorkWeek' | 'Month' | 'Agenda';
        const baseDate = inst.selectedDate as Date;
        if (baseDate) {
          if (view === 'Day' || view === 'Agenda') {
            startRange = new Date(baseDate);
            startRange.setHours(0, 0, 0, 0);
            endRange = new Date(baseDate);
            endRange.setHours(23, 59, 59, 999);
          } else if (view === 'Week' || view === 'WorkWeek') {
            const day = baseDate.getDay();
            const diffToMonday = (day + 6) % 7; // Monday=0
            startRange = new Date(baseDate);
            startRange.setDate(baseDate.getDate() - diffToMonday);
            startRange.setHours(0, 0, 0, 0);
            endRange = new Date(startRange);
            endRange.setDate(startRange.getDate() + 6);
            endRange.setHours(23, 59, 59, 999);
          } else if (view === 'Month') {
            startRange = new Date(baseDate.getFullYear(), baseDate.getMonth(), 1, 0, 0, 0, 0);
            endRange = new Date(baseDate.getFullYear(), baseDate.getMonth() + 1, 0, 23, 59, 59, 999);
          }
        }
      }
      if (!startRange || !endRange) {
        startRange = fallbackStart;
        endRange = fallbackEnd;
      }
      // Always request non-expanded events (expand=0)
      const data = await fetchEvents(selectedGroupId, showInactive, {
        start: startRange!,
        end: endRange!,
        expand: false,
      });
      const mapped: Event[] = data.map((e: RawEvent) => ({
        Id: e.Id,
        Subject: e.Subject,
        StartTime: parseEventDate(e.StartTime),
        EndTime: parseEventDate(e.EndTime),
        IsAllDay: e.IsAllDay,
        MediaId: e.MediaId,
        Icon: e.Icon,
        Type: e.Type,
        OccurrenceOfId: e.OccurrenceOfId,
        Recurrence: !!e.RecurrenceRule,
        RecurrenceRule: e.RecurrenceRule ?? null,
        RecurrenceEnd: e.RecurrenceEnd ?? null,
        SkipHolidays: e.SkipHolidays ?? false,
        RecurrenceException: e.RecurrenceException ?? undefined,
        recurrenceException: e.RecurrenceException ?? undefined, // for Syncfusion
      }));
      setEvents(mapped);
    } catch (err) {
      console.error('Fehler beim Laden der Termine:', err);
    }
  }, [selectedGroupId, showInactive]);

  React.useEffect(() => {
    if (selectedGroupId) {
      // selectedGroupId kann null sein, fetchEvents erwartet aber string
      fetchAndSetEvents();
    } else {
      setEvents([]);
    }
  }, [selectedGroupId, showInactive, fetchAndSetEvents]);

  // Helper: prüfe, ob Zeitraum einen Feiertag/Ferienbereich schneidet
  const isWithinHolidayRange = React.useCallback(
    (start: Date, end: Date) => {
      // normalisiere Endzeit minimal (Syncfusion nutzt exklusive Enden in einigen Fällen)
      const adjEnd = new Date(end);
      // keine Änderung nötig – unsere eigenen Events sind präzise
      for (const h of holidays) {
        // Holiday dates are strings YYYY-MM-DD (local date)
        const hs = new Date(h.start_date + 'T00:00:00');
        const he = new Date(h.end_date + 'T23:59:59');
        if (
          (start >= hs && start <= he) ||
          (adjEnd >= hs && adjEnd <= he) ||
          (start <= hs && adjEnd >= he)
        ) {
          return true;
        }
      }
      return false;
    },
    [holidays]
  );

  // Baue Holiday-Anzeige-Events und Block-Events
  const holidayDisplayEvents: Event[] = useMemo(() => {
    if (!showHolidayList) return [];
    const out: Event[] = [];
    for (const h of holidays) {
      const start = new Date(h.start_date + 'T00:00:00');
      const end = new Date(h.end_date + 'T23:59:59');
      out.push({
        Id: `holiday-${h.id}-display`,
        Subject: h.name,
        StartTime: start,
        EndTime: end,
        IsAllDay: true,
        isHoliday: true,
      });
    }
    return out;
  }, [holidays, showHolidayList]);

  const holidayBlockEvents: Event[] = useMemo(() => {
    if (allowScheduleOnHolidays) return [];
    const out: Event[] = [];
    for (const h of holidays) {
      const start = new Date(h.start_date + 'T00:00:00');
      const end = new Date(h.end_date + 'T23:59:59');
      out.push({
        Id: `holiday-${h.id}-block`,
        Subject: h.name,
        StartTime: start,
        EndTime: end,
        IsAllDay: true,
        IsBlock: true,
        isHoliday: true,
      });
    }
    return out;
  }, [holidays, allowScheduleOnHolidays]);

  const dataSource = useMemo(() => {
    // Filter: Events with SkipHolidays=true are never shown on holidays, regardless of toggle
    const filteredEvents = events.filter(ev => {
      if (ev.SkipHolidays) {
        // If event falls within a holiday, hide it
        const s = ev.StartTime instanceof Date ? ev.StartTime : new Date(ev.StartTime);
        const e = ev.EndTime instanceof Date ? ev.EndTime : new Date(ev.EndTime);
        for (const h of holidays) {
          const hs = new Date(h.start_date + 'T00:00:00');
          const he = new Date(h.end_date + 'T23:59:59');
          if (
            (s >= hs && s <= he) ||
            (e >= hs && e <= he) ||
            (s <= hs && e >= he)
          ) {
            return false;
          }
        }
      }
      return true;
    });
    return [...filteredEvents, ...holidayDisplayEvents, ...holidayBlockEvents];
  }, [events, holidayDisplayEvents, holidayBlockEvents, holidays]);

  // Removed dataSource logging

  // Aktive akademische Periode für Datum aus dem Backend ermitteln
  const refreshAcademicPeriodFor = React.useCallback(
    async (baseDate: Date) => {
      try {
        const p = await getAcademicPeriodForDate(baseDate);
        if (!p) {
          setSchoolYearLabel('');
          setHasSchoolYearPlan(false);
          return;
        }
        // Anzeige: bevorzugt display_name, sonst name
        const label = p.display_name ? p.display_name : p.name;
        setSchoolYearLabel(label);
        // Existiert ein Ferienplan innerhalb der Periode?
        const start = new Date(p.start_date + 'T00:00:00');
        const end = new Date(p.end_date + 'T23:59:59');
        let exists = false;
        for (const h of holidays) {
          const hs = new Date(h.start_date + 'T00:00:00');
          const he = new Date(h.end_date + 'T23:59:59');
          if (hs <= end && he >= start) {
            exists = true;
            break;
          }
        }
        setHasSchoolYearPlan(exists);
      } catch (e) {
        console.error('Akademische Periode laden fehlgeschlagen:', e);
        setSchoolYearLabel('');
        setHasSchoolYearPlan(false);
      }
    },
    [holidays]
  );

  // Anzahl an Ferienzeiträumen in aktueller Ansicht ermitteln + Perioden-Indikator setzen
  const updateHolidaysInView = React.useCallback(() => {
    const inst = scheduleRef.current;
    if (!inst) {
      setHolidaysInView(0);
      return;
    }
    const view = inst.currentView as 'Day' | 'Week' | 'WorkWeek' | 'Month' | 'Agenda';
    const baseDate = inst.selectedDate as Date;
    if (!baseDate) {
      setHolidaysInView(0);
      return;
    }
    let rangeStart = new Date(baseDate);
    let rangeEnd = new Date(baseDate);
    if (view === 'Day' || view === 'Agenda') {
      rangeStart.setHours(0, 0, 0, 0);
      rangeEnd.setHours(23, 59, 59, 999);
    } else if (view === 'Week' || view === 'WorkWeek') {
      const day = baseDate.getDay();
      const diffToMonday = (day + 6) % 7; // Monday=0
      rangeStart = new Date(baseDate);
      rangeStart.setDate(baseDate.getDate() - diffToMonday);
      rangeStart.setHours(0, 0, 0, 0);
      rangeEnd = new Date(rangeStart);
      rangeEnd.setDate(rangeStart.getDate() + 6);
      rangeEnd.setHours(23, 59, 59, 999);
    } else if (view === 'Month') {
      rangeStart = new Date(baseDate.getFullYear(), baseDate.getMonth(), 1, 0, 0, 0, 0);
      rangeEnd = new Date(baseDate.getFullYear(), baseDate.getMonth() + 1, 0, 23, 59, 59, 999);
    }
    let count = 0;
    for (const h of holidays) {
      const hs = new Date(h.start_date + 'T00:00:00');
      const he = new Date(h.end_date + 'T23:59:59');
      const overlaps =
        (hs >= rangeStart && hs <= rangeEnd) ||
        (he >= rangeStart && he <= rangeEnd) ||
        (hs <= rangeStart && he >= rangeEnd);
      if (overlaps) count += 1;
    }
    setHolidaysInView(count);
    // Perioden-Indikator über Backend prüfen
    refreshAcademicPeriodFor(baseDate);
  }, [holidays, refreshAcademicPeriodFor]);

  // Aktualisiere Indikator wenn Ferien oder Ansicht (Key) wechseln
  React.useEffect(() => {
    updateHolidaysInView();
  }, [holidays, updateHolidaysInView, schedulerKey]);

  return (
    <div>
      <h1 style={{ fontSize: '1.5rem', fontWeight: 700, marginBottom: 16 }}>Terminmanagement</h1>
      <div
        style={{
          marginBottom: 16,
          display: 'flex',
          alignItems: 'center',
          gap: 16,
          flexWrap: 'wrap',
        }}
      >
        <label htmlFor="groupDropdown" className="mb-0 mr-2" style={{ whiteSpace: 'nowrap' }}>
          Raumgruppe auswählen:
        </label>
        <DropDownListComponent
          id="groupDropdown"
          dataSource={groups}
          fields={{ text: 'name', value: 'id' }}
          placeholder="Gruppe auswählen"
          value={selectedGroupId}
          width="240px"
          change={(e: { value: string }) => {
            // <--- Typ für e ergänzt
            setEvents([]); // Events sofort leeren
            setSelectedGroupId(e.value);
          }}
          style={{}}
        />

        {/* Akademische Periode Selector + Plan-Badge */}
        <span style={{ marginLeft: 8, whiteSpace: 'nowrap' }}>Periode:</span>
        <DropDownListComponent
          id="periodDropdown"
          dataSource={periods}
          fields={{ text: 'label', value: 'id' }}
          placeholder="Periode wählen"
          value={activePeriodId ?? undefined}
          width="260px"
          change={async (e: { value: number }) => {
            const id = Number(e.value);
            if (!id) return;
            try {
              const updated = await setActiveAcademicPeriod(id);
              setActivePeriodId(updated.id);
              // Zum gleichen Tag/Monat (heute) innerhalb der gewählten Periode springen
              const today = new Date();
              const targetYear = new Date(updated.start_date).getFullYear();
              const target = new Date(targetYear, today.getMonth(), today.getDate(), 12, 0, 0);
              if (scheduleRef.current) {
                scheduleRef.current.selectedDate = target;
                scheduleRef.current.dataBind?.();
              }
              updateHolidaysInView();
            } catch (err) {
              console.error('Aktive Periode setzen fehlgeschlagen:', err);
            }
          }}
          style={{}}
        />
        {/* School-year/period plan badge (adjacent) */}
        <span
          title={hasSchoolYearPlan ? 'Ferienplan ist hinterlegt' : 'Kein Ferienplan hinterlegt'}
          style={{
            background: hasSchoolYearPlan ? '#dcfce7' : '#f3f4f6',
            border: hasSchoolYearPlan ? '1px solid #86efac' : '1px solid #e5e7eb',
            color: '#000',
            padding: '4px 10px',
            borderRadius: 16,
            fontSize: 12,
            display: 'flex',
            alignItems: 'center',
            gap: 6,
          }}
        >
          {hasSchoolYearPlan ? (
            <CheckCircle size={14} color="#166534" />
          ) : (
            <AlertCircle size={14} color="#6b7280" />
          )}
          {schoolYearLabel || 'Periode'}
        </span>
      </div>
      <button
        className="e-btn e-success mb-4"
        onClick={() => {
          const now = new Date();
          // Runde auf die nächste halbe Stunde
          const minutes = now.getMinutes();
          const roundedMinutes = minutes < 30 ? 30 : 0;
          const startTime = new Date(now);
          startTime.setMinutes(roundedMinutes, 0, 0);
          if (roundedMinutes === 0) startTime.setHours(startTime.getHours() + 1);

          const endTime = new Date(startTime);
          endTime.setMinutes(endTime.getMinutes() + 30);

          setModalInitialData({
            startDate: startTime,
            startTime: startTime,
            endTime: endTime,
          });
          setEditMode(false);
          setModalOpen(true);
        }}
      >
        Neuen Termin anlegen
      </button>
      <div
        style={{
          display: 'flex',
          alignItems: 'center',
          gap: 24,
          marginBottom: 16,
          flexWrap: 'wrap',
        }}
      >
        <label>
          <input
            type="checkbox"
            checked={showInactive}
            onChange={e => setShowInactive(e.target.checked)}
            style={{ marginRight: 8 }}
          />
          Vergangene Termine anzeigen
        </label>
        <label>
          <input
            type="checkbox"
            checked={allowScheduleOnHolidays}
            onChange={e => setAllowScheduleOnHolidays(e.target.checked)}
            style={{ marginRight: 8 }}
          />
          Termine an Ferientagen erlauben
        </label>
        <label>
          <input
            type="checkbox"
            checked={showHolidayList}
            onChange={e => setShowHolidayList(e.target.checked)}
            style={{ marginRight: 8 }}
          />
          Ferien im Kalender anzeigen
        </label>
        {/* Removed expandRecurrences toggle: Syncfusion now always handles recurrence */}
        {/* Right-aligned indicators */}
        <div style={{ marginLeft: 'auto', display: 'flex', gap: 8, alignItems: 'center' }}>
          {/* Holidays-in-view badge */}
          <span
            title="Anzahl der Ferientage/-zeiträume in der aktuellen Ansicht"
            style={{
              background: holidaysInView > 0 ? '#ffe8cc' : '#f3f4f6',
              border: holidaysInView > 0 ? '1px solid #ffcf99' : '1px solid #e5e7eb',
              color: '#000',
              padding: '4px 10px',
              borderRadius: 16,
              fontSize: 12,
            }}
          >
            {holidaysInView > 0 ? `Ferien im Blick: ${holidaysInView}` : 'Keine Ferien in Ansicht'}
          </span>
        </div>
        {/* Removed expandRecurrences indicator: Syncfusion now always handles recurrence */}
      </div>
      <CustomEventModal
        open={modalOpen}
        onClose={() => {
          setModalOpen(false);
          setEditMode(false); // Editiermodus zurücksetzen
        }}
        onSave={async () => {
          setModalOpen(false);
          setEditMode(false);
          // Reload events using the same logic as fetchAndSetEvents
          await fetchAndSetEvents();
          setSchedulerKey(prev => prev + 1); // <-- Key erhöhen
        }}
        initialData={modalInitialData}
        groupName={groups.find(g => g.id === selectedGroupId) ?? { id: selectedGroupId, name: '' }}
        groupColor={selectedGroupId ? getGroupColor(selectedGroupId, groups) : undefined}
        editMode={editMode} // NEU: Prop für Editiermodus
        blockHolidays={!allowScheduleOnHolidays}
        isHolidayRange={(s, e) => isWithinHolidayRange(s, e)}
      />
      <ScheduleComponent
        ref={scheduleRef}
        key={schedulerKey} // <-- dynamischer Key
        height="750px"
        locale="de"
        currentView="Week"
        eventSettings={{
          dataSource: dataSource,
          fields: {
            id: 'Id',
            subject: 'Subject',
            startTime: 'StartTime',
            endTime: 'EndTime',
            isBlock: 'IsBlock',
          },
          template: eventTemplate, // <--- Hier das Template setzen!
        }}
        actionComplete={(args) => {
          updateHolidaysInView();
          // Bei Navigation oder Viewwechsel Events erneut laden (für Range-basierte Expansion)
          if (args && (args.requestType === 'dateNavigate' || args.requestType === 'viewNavigate')) {
            fetchAndSetEvents();
          }
        }}
        cellClick={args => {
          if (!allowScheduleOnHolidays && isWithinHolidayRange(args.startTime, args.endTime)) {
            args.cancel = true;
            return; // block creation on holidays
          }
          // args.startTime und args.endTime sind Date-Objekte
          args.cancel = true; // Verhindert die Standardaktion
          setModalInitialData({
            startDate: args.startTime,
            startTime: args.startTime,
            endTime: args.endTime,
          });
          setEditMode(false); // NEU: kein Editiermodus
          setModalOpen(true);
        }}
        popupOpen={async args => {
          if (args.type === 'Editor') {
            args.cancel = true;
            const event = args.data;
            // Removed event logging
            let media = null;
            if (event.MediaId) {
              try {
                const mediaData = await fetchMediaById(event.MediaId);
                media = {
                  id: mediaData.id,
                  path: mediaData.file_path,
                  name: mediaData.name || mediaData.url,
                };
              } catch (err) {
                console.error('Fehler beim Laden der Mediainfos:', err);
              }
            }
            // Parse recurrence info if present (supports FREQ=WEEKLY;BYDAY=...;[UNTIL=...])
            let repeat = false;
            let weekdays: number[] = [];
            let repeatUntil: Date | null = null;
            const rr = (event.RecurrenceRule as string) || '';
            if (rr && rr.includes('FREQ=WEEKLY')) {
              repeat = true;
              const m = rr.match(/BYDAY=([^;]+)/);
              if (m && m[1]) {
                const map: Record<string, number> = { MO: 0, TU: 1, WE: 2, TH: 3, FR: 4, SA: 5, SU: 6 };
                weekdays = m[1].split(',').map(s => map[s]).filter(v => v !== undefined);
              }
              const mu = rr.match(/UNTIL=([0-9TZ]+)/);
              if (mu && mu[1]) {
                // UNTIL is UTC in yyyymmddThhmmssZ form; we take date part
                const untilIso = mu[1]
                  .replace(/^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})Z$/, '$1-$2-$3T$4:$5:$6Z');
                repeatUntil = new Date(untilIso);
              } else if (event.RecurrenceEnd) {
                repeatUntil = new Date(event.RecurrenceEnd);
              }
            }

            setModalInitialData({
              Id: event.Id,
              title: event.Subject,
              startDate: event.StartTime,
              startTime: event.StartTime,
              endTime: event.EndTime,
              description: event.Description ?? '',
              type: event.Type ?? 'presentation',
              repeat,
              weekdays,
              repeatUntil,
              skipHolidays: event.SkipHolidays ?? false,
              media, // Metadaten werden nur bei Bedarf geladen!
              slideshowInterval: event.SlideshowInterval ?? 10,
              websiteUrl: event.WebsiteUrl ?? '',
            });
            // Removed modal initial data logging
            setEditMode(true);
            setModalOpen(true);
          }
        }}
        eventRendered={(args: EventRenderedArgs) => {
          // Always hide events that skip holidays when they fall on holidays, regardless of toggle
          if (args.data) {
            const ev = args.data as unknown as Partial<Event>;
            if (ev.SkipHolidays && !args.data.isHoliday) {
            const s =
              args.data.StartTime instanceof Date
                ? args.data.StartTime
                : new Date(args.data.StartTime);
            const e =
              args.data.EndTime instanceof Date ? args.data.EndTime : new Date(args.data.EndTime);
            if (isWithinHolidayRange(s, e)) {
              args.cancel = true;
              return;
            }
            }
          }

          // Blende Nicht-Ferien-Events aus, falls sie in Ferien fallen und Terminieren nicht erlaubt ist
          // Hide events on holidays if not allowed
          if (!allowScheduleOnHolidays && args.data && !args.data.isHoliday) {
            const s =
              args.data.StartTime instanceof Date
                ? args.data.StartTime
                : new Date(args.data.StartTime);
            const e =
              args.data.EndTime instanceof Date ? args.data.EndTime : new Date(args.data.EndTime);
            if (isWithinHolidayRange(s, e)) {
              args.cancel = true;
              return;
            }
          }

          if (selectedGroupId && args.data && args.data.Id) {
            const groupColor = getGroupColor(selectedGroupId, groups);
            const now = new Date();

            // Vergangene Termine: Raumgruppenfarbe
            if (args.data.EndTime && args.data.EndTime < now) {
              args.element.style.backgroundColor = groupColor ? `${groupColor}` : '#f3f3f3';
              args.element.style.color = '#000';
            } else if (groupColor) {
              args.element.style.backgroundColor = groupColor;
              args.element.style.color = '#000';
            }

            // Spezielle Darstellung für Ferienanzeige-Events
            if (args.data.isHoliday && !args.data.IsBlock) {
              args.element.style.backgroundColor = '#ffe8cc'; // sanftes Orange
              args.element.style.border = '1px solid #ffcf99';
              args.element.style.color = '#000';
            }
            // Gleiche Darstellung für Ferien-Block-Events
            if (args.data.isHoliday && args.data.IsBlock) {
              args.element.style.backgroundColor = '#ffe8cc';
              args.element.style.border = '1px solid #ffcf99';
              args.element.style.color = '#000';
            }
          }
        }}
        actionBegin={async (args: ActionEventArgs) => {
          if (args.requestType === 'eventRemove') {
            // args.data ist ein Array von zu löschenden Events
            const toDelete = Array.isArray(args.data) ? args.data : [args.data];
            for (const ev of toDelete) {
              try {
                await deleteEvent(ev.Id); // Deine API-Funktion
              } catch (err) {
                // Optional: Fehlerbehandlung
                console.error('Fehler beim Löschen:', err);
              }
            }
            // Events nach Löschen neu laden
            if (selectedGroupId) {
              fetchEvents(selectedGroupId, showInactive)
                .then((data: RawEvent[]) => {
                  const mapped: Event[] = data.map((e: RawEvent) => ({
                    Id: e.Id,
                    Subject: e.Subject,
                    StartTime: parseEventDate(e.StartTime),
                    EndTime: parseEventDate(e.EndTime),
                    IsAllDay: e.IsAllDay,
                    MediaId: e.MediaId,
                    SkipHolidays: e.SkipHolidays ?? false,
                  }));
                  setEvents(mapped);
                })
                .catch(console.error);
            }
            // Syncfusion soll das Event nicht selbst löschen
            args.cancel = true;
          } else if (
            (args.requestType === 'eventCreate' || args.requestType === 'eventChange') &&
            !allowScheduleOnHolidays
          ) {
            // Verhindere Erstellen/Ändern in Ferienbereichen (Failsafe, falls eingebauter Editor genutzt wird)
            type PartialEventLike = { StartTime?: Date | string; EndTime?: Date | string };
            const raw = (args as ActionEventArgs).data as
              | PartialEventLike
              | PartialEventLike[]
              | undefined;
            const data = Array.isArray(raw) ? raw[0] : raw;
            if (data && data.StartTime && data.EndTime) {
              const s = data.StartTime instanceof Date ? data.StartTime : new Date(data.StartTime);
              const e = data.EndTime instanceof Date ? data.EndTime : new Date(data.EndTime);
              if (isWithinHolidayRange(s, e)) {
                args.cancel = true;
                return;
              }
            }
          }
        }}
        firstDayOfWeek={1}
        renderCell={(args: RenderCellEventArgs) => {
          // Nur für Arbeitszellen (Stunden-/Tageszellen)
          if (args.elementType === 'workCells') {
            const now = new Date();
            // args.element ist vom Typ Element, daher als HTMLElement casten:
            const cell = args.element as HTMLElement;
            if (args.date && args.date < now) {
              cell.style.backgroundColor = '#fff9e3'; // Hellgelb für Vergangenheit
              cell.style.opacity = '0.7';
            }
          }
        }}
      >
        <ViewsDirective>
          <ViewDirective option="Day" />
          <ViewDirective option="Week" />
          <ViewDirective option="WorkWeek" />
          <ViewDirective option="Month" />
          <ViewDirective option="Agenda" />
        </ViewsDirective>
        <Inject services={[Day, Week, WorkWeek, Month, Agenda]} />
      </ScheduleComponent>
    </div>
  );
};

export default Appointments;
