export const formatData = (rawData) => {
  const weekdays = [
    "Sonntag",
    "Montag",
    "Dienstag",
    "Mittwoch",
    "Donnerstag",
    "Freitag",
    "Samstag",
  ];

  const MERGE_GAP_MINUTES = 15;

  function formatTime(time) {
    if (time === null || time === undefined) return "–";
    const n = Number(time);
    if (!Number.isFinite(n)) return "–";
    const str = String(time).padStart(4, "0");
    return str.slice(0, 2) + ":" + str.slice(2);
  }

  function formatDate(date) {
    if (date === null || date === undefined) return "–";
    const str = String(date);
    if (str.length < 8) return "–";
    return str.slice(6, 8) + "." + str.slice(4, 6) + "." + str.slice(0, 4);
  }

  function getWeekday(date) {
    if (date === null || date === undefined) return "–";
    const str = String(date);
    if (str.length < 8) return "–";
    const d = new Date(str.slice(0, 4), str.slice(4, 6) - 1, str.slice(6, 8));
    if (Number.isNaN(d.getTime())) return "–";
    return weekdays[d.getDay()];
  }

  function parseTimeToMinutes(timeStr) {
    if (!timeStr || timeStr === "–") return null;
    const [h, m] = String(timeStr).split(":");
    const hh = Number(h);
    const mm = Number(m);
    if (!Number.isFinite(hh) || !Number.isFinite(mm)) return null;
    if (hh < 0 || hh > 23 || mm < 0 || mm > 59) return null;
    return hh * 60 + mm;
  }

  function dateKeyFromFormatted(dateStr) {
    if (!dateStr || dateStr === "–") return null;
    const [dd, mm, yyyy] = String(dateStr).split(".");
    const d = Number(dd);
    const m = Number(mm);
    const y = Number(yyyy);
    if (!Number.isFinite(d) || !Number.isFinite(m) || !Number.isFinite(y)) {
      return null;
    }
    return y * 10000 + m * 100 + d;
  }

  const items = rawData?.result ?? [];
  const lessons = [];

  for (const item of items) {
    if (item?.activityType !== "Unterricht") continue;

    const subject = item?.su?.[0]?.name ?? "–";
    const normalizedSubject = String(subject).trimStart();
    const isSz = normalizedSubject.startsWith("SZ");

    const cancelled =
      String(item?.code ?? "")
        .trim()
        .toLowerCase() === "cancelled";

    lessons.push({
      room: item?.ro?.[0]?.name ?? "–",
      teacher: item?.te?.[0]?.name ?? "–",
      subject,
      startTime: formatTime(item?.startTime),
      endTime: formatTime(item?.endTime),
      weekday: getWeekday(item?.date),
      date: formatDate(item?.date),
      cancelled,

      // internal fields for grouping/sorting
      _dateRaw: Number(item?.date) || 0,
      _startTimeRaw: Number(item?.startTime) || 0,
      _endTimeRaw: Number(item?.endTime) || 0,
      _isSz: isSz,
    });
  }

  lessons.sort((a, b) => {
    if (a._dateRaw !== b._dateRaw) return a._dateRaw - b._dateRaw;
    if (a._startTimeRaw !== b._startTimeRaw)
      return a._startTimeRaw - b._startTimeRaw;
    return a._endTimeRaw - b._endTimeRaw;
  });

  // Group by same day + same start time.
  // If any subject in a group starts with "SZ", collapse the whole group into the SZ lesson.
  const groups = new Map();
  for (const lesson of lessons) {
    const key = `${lesson._dateRaw}-${lesson._startTimeRaw}`;
    const group = groups.get(key);
    if (group) group.push(lesson);
    else groups.set(key, [lesson]);
  }

  const timetable = [];

  for (const group of groups.values()) {
    const hasSz = group.some((l) => l._isSz);
    if (!hasSz) {
      for (const lesson of group) {
        const { _dateRaw, _startTimeRaw, _endTimeRaw, _isSz, ...publicLesson } =
          lesson;
        timetable.push(publicLesson);
      }
      continue;
    }

    // Normalize: if any SZ* exists, show exactly one SZ block for that slot.
    const base = group.find((l) => l._isSz) ?? group[0];
    const maxEndRaw = group.reduce(
      (max, l) => (l._endTimeRaw > max ? l._endTimeRaw : max),
      0,
    );
    const cancelled = group.every((l) => l.cancelled);

    timetable.push({
      room: "-",
      teacher: "-",
      subject: "SZ",
      startTime: base.startTime,
      endTime: maxEndRaw ? formatTime(maxEndRaw) : base.endTime,
      weekday: base.weekday,
      date: base.date,
      cancelled,
    });
  }

  // Merge double lessons (same subject/teacher/room/day) that are consecutive
  // (allows a short gap, e.g. breaks).
  const bucketKey = (e) =>
    `${e.date}|${e.weekday}|${e.subject}|${e.teacher}|${e.room}`;

  const buckets = new Map();
  for (const entry of timetable) {
    const key = bucketKey(entry);
    const arr = buckets.get(key);
    if (arr) arr.push(entry);
    else buckets.set(key, [entry]);
  }

  const merged = [];

  for (const arr of buckets.values()) {
    arr.sort((a, b) => {
      const as = parseTimeToMinutes(a.startTime) ?? 0;
      const bs = parseTimeToMinutes(b.startTime) ?? 0;
      if (as !== bs) return as - bs;
      const ae = parseTimeToMinutes(a.endTime) ?? 0;
      const be = parseTimeToMinutes(b.endTime) ?? 0;
      return ae - be;
    });

    const mergedArr = [];
    for (const entry of arr) {
      const prev = mergedArr[mergedArr.length - 1];
      if (!prev) {
        mergedArr.push(entry);
        continue;
      }

      const prevEnd = parseTimeToMinutes(prev.endTime);
      const currStart = parseTimeToMinutes(entry.startTime);
      const currEnd = parseTimeToMinutes(entry.endTime);

      const canMergeTimes =
        prevEnd !== null &&
        currStart !== null &&
        currEnd !== null &&
        currStart >= prevEnd &&
        currStart - prevEnd <= MERGE_GAP_MINUTES;

      if (canMergeTimes) {
        prev.endTime = entry.endTime;
        prev.cancelled = Boolean(prev.cancelled) || Boolean(entry.cancelled);
        continue;
      }

      mergedArr.push(entry);
    }

    merged.push(...mergedArr);
  }

  merged.sort((a, b) => {
    const ad = dateKeyFromFormatted(a.date) ?? 0;
    const bd = dateKeyFromFormatted(b.date) ?? 0;
    if (ad !== bd) return ad - bd;
    const as = parseTimeToMinutes(a.startTime) ?? 0;
    const bs = parseTimeToMinutes(b.startTime) ?? 0;
    if (as !== bs) return as - bs;

    // stable-ish: keep similar subjects grouped
    const subj = String(a.subject).localeCompare(String(b.subject));
    if (subj !== 0) return subj;
    const room = String(a.room).localeCompare(String(b.room));
    if (room !== 0) return room;
    return String(a.teacher).localeCompare(String(b.teacher));
  });

  return merged;
};
