import React, { useEffect, useMemo, useState } from "react";

const DATA = {
  saturday: {
    label: "Zaterdag",
    date: "16 mei",
    start: "12:00",
    end: "23:00",
    stages: ["AREA.97", "AREA.01", "AREA.07", "AREA.14", "AREA.22", "AREA.24"],
    events: [
      { stage: "AREA.97", start: "12:00", end: "14:00", title: "Luna Ludmila" },
      { stage: "AREA.97", start: "14:00", end: "15:45", title: "Shed vs Head High" },
      { stage: "AREA.97", start: "15:45", end: "17:30", title: "Rod x Sterac", note: "Detroit techno set" },
      { stage: "AREA.97", start: "17:30", end: "19:00", title: "Joris Voorn", note: "Vinyl only techno set" },
      { stage: "AREA.97", start: "19:00", end: "21:00", title: "Alarico x Ben Klock" },
      { stage: "AREA.97", start: "21:00", end: "23:00", title: "Collabs 3000", note: "Chris Liebing & Speedy J" },

      { stage: "AREA.01", start: "12:00", end: "14:30", title: "Varuna Agosti" },
      { stage: "AREA.01", start: "14:30", end: "16:30", title: "DJ Red" },
      { stage: "AREA.01", start: "16:30", end: "18:15", title: "Andy Martin" },
      { stage: "AREA.01", start: "18:15", end: "20:15", title: "Len Faki x Quest" },
      { stage: "AREA.01", start: "20:15", end: "21:30", title: "Planetary Assault Systems", note: "Live" },
      { stage: "AREA.01", start: "21:30", end: "23:00", title: "Rene Wise" },

      { stage: "AREA.07", start: "12:00", end: "14:00", title: "Fiene" },
      { stage: "AREA.07", start: "14:00", end: "16:00", title: "Emilija x Fenrick" },
      { stage: "AREA.07", start: "16:00", end: "17:45", title: "Noise Mafia x Peterblue" },
      { stage: "AREA.07", start: "17:45", end: "19:30", title: "Fumi x SPFDJ" },
      { stage: "AREA.07", start: "19:30", end: "21:30", title: "Kobosil x Ornella" },
      { stage: "AREA.07", start: "21:30", end: "23:00", title: "DIØN" },

      { stage: "AREA.14", start: "12:00", end: "14:00", title: "Essy" },
      { stage: "AREA.14", start: "14:00", end: "15:45", title: "Dr. G" },
      { stage: "AREA.14", start: "15:45", end: "17:15", title: "BIIANCO" },
      { stage: "AREA.14", start: "17:15", end: "19:00", title: "DJ Boring" },
      { stage: "AREA.14", start: "19:00", end: "21:00", title: "Cybersex" },
      { stage: "AREA.14", start: "21:00", end: "23:00", title: "Ellen Allien" },

      { stage: "AREA.22", start: "12:00", end: "14:00", title: "Morgan" },
      { stage: "AREA.22", start: "14:00", end: "16:00", title: "Naone" },
      { stage: "AREA.22", start: "16:00", end: "18:00", title: "Alarico", note: "Presents Kenji Hina" },
      { stage: "AREA.22", start: "18:00", end: "19:00", title: "Sweely" },
      { stage: "AREA.22", start: "19:00", end: "21:00", title: "Ryan Elliott" },
      { stage: "AREA.22", start: "21:00", end: "23:00", title: "Blasha & Allatt", note: "House set" },

      { stage: "AREA.24", start: "12:00", end: "14:00", title: "Prance" },
      { stage: "AREA.24", start: "14:00", end: "16:00", title: "Undivulged: Beau Didier, Flits, Isaiah & Lasse", note: "F2F set" },
      { stage: "AREA.24", start: "16:00", end: "17:00", title: "Dold", note: "Live" },
      { stage: "AREA.24", start: "17:00", end: "19:00", title: "Ogazón", note: "Techno set" },
      { stage: "AREA.24", start: "19:00", end: "20:00", title: "Chontane", note: "Live" },
      { stage: "AREA.24", start: "20:00", end: "23:00", title: "Hayes Collective: Cravo, Nørbak, Temudo & Vil", note: "F2F set" },
    ],
  },
  sunday: {
    label: "Zondag",
    date: "17 mei",
    start: "13:00",
    end: "23:00",
    stages: ["AREA.97", "AREA.01", "AREA.07", "AREA.14", "AREA.22", "AREA.24"],
    events: [
      { stage: "AREA.97", start: "13:00", end: "14:30", title: "Twiena" },
      { stage: "AREA.97", start: "14:30", end: "16:00", title: "Beste Hira x Lobster" },
      { stage: "AREA.97", start: "16:00", end: "17:45", title: "Annē x Ben Sims" },
      { stage: "AREA.97", start: "17:45", end: "19:30", title: "Anetha x Pegassi" },
      { stage: "AREA.97", start: "19:30", end: "21:30", title: "Ben UFO x Four Tet" },
      { stage: "AREA.97", start: "21:30", end: "23:00", title: "Nina Kraviz" },

      { stage: "AREA.01", start: "13:00", end: "14:45", title: "Remma x Thoms Traxx" },
      { stage: "AREA.01", start: "14:45", end: "16:15", title: "Cio d'Or x Claudio PRC" },
      { stage: "AREA.01", start: "16:15", end: "18:00", title: "Abstract Division x JakoJako" },
      { stage: "AREA.01", start: "18:00", end: "19:30", title: "LSD", note: "Live" },
      { stage: "AREA.01", start: "19:30", end: "21:00", title: "Ignez x Rødhåd", note: "Live" },
      { stage: "AREA.01", start: "21:00", end: "23:00", title: "Freddy K x Marrøn" },

      { stage: "AREA.07", start: "13:00", end: "15:00", title: "Alycia Bezgo" },
      { stage: "AREA.07", start: "15:00", end: "16:45", title: "Faster Horses x Stef de Haan" },
      { stage: "AREA.07", start: "16:45", end: "17:45", title: "The Tunegirl", note: "Live" },
      { stage: "AREA.07", start: "17:45", end: "19:30", title: "Adrián Mills", note: "Presents 2High" },
      { stage: "AREA.07", start: "19:30", end: "21:15", title: "Ciara Cuvé" },
      { stage: "AREA.07", start: "21:15", end: "23:00", title: "AZYR x Charlie Sparks" },

      { stage: "AREA.14", start: "13:00", end: "14:30", title: "Kyra Khaldi" },
      { stage: "AREA.14", start: "14:30", end: "15:45", title: "Aldonna" },
      { stage: "AREA.14", start: "15:45", end: "17:00", title: "Main Phase" },
      { stage: "AREA.14", start: "17:00", end: "18:30", title: "Milion" },
      { stage: "AREA.14", start: "18:30", end: "20:00", title: "Emvae x Moxes" },
      { stage: "AREA.14", start: "20:00", end: "21:30", title: "Helena Lauwært" },
      { stage: "AREA.14", start: "21:30", end: "23:00", title: "Sam Alfred" },

      { stage: "AREA.22", start: "13:00", end: "14:45", title: "Hannecart" },
      { stage: "AREA.22", start: "14:45", end: "16:30", title: "Rene Wise", note: "House set" },
      { stage: "AREA.22", start: "16:30", end: "17:30", title: "Paranoid London", note: "Live" },
      { stage: "AREA.22", start: "17:30", end: "19:15", title: "Freddy K", note: "House set" },
      { stage: "AREA.22", start: "19:15", end: "21:15", title: "Doudou MD x Jennifer Loveless" },
      { stage: "AREA.22", start: "21:15", end: "23:00", title: "DJ Sweet6teen" },

      { stage: "AREA.24", start: "13:00", end: "14:30", title: "Karina Schneider" },
      { stage: "AREA.24", start: "14:30", end: "16:15", title: "JSPRV35 x Toobris" },
      { stage: "AREA.24", start: "16:15", end: "17:15", title: "UFO95", note: "Live" },
      { stage: "AREA.24", start: "17:15", end: "19:00", title: "Kamelia x Setaoc Mass" },
      { stage: "AREA.24", start: "19:00", end: "20:30", title: "Colin Benders x Dasha Rush", note: "Live" },
      { stage: "AREA.24", start: "20:30", end: "23:00", title: "Jeans x Spekki Webu x Woody92" },
    ],
  },
};

const PX_PER_MINUTE = 1.05;

function timeToMinutes(time) {
  const [hours, minutes] = time.split(":").map(Number);
  return hours * 60 + minutes;
}

function minutesToTime(total) {
  const hours = Math.floor(total / 60);
  const minutes = total % 60;
  return `${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}`;
}

function addIds() {
  Object.entries(DATA).forEach(([dayKey, day]) => {
    day.events.forEach((event, index) => {
      event.day = dayKey;
      event.id = `${dayKey}-${index}-${event.stage}-${event.start}-${event.title}`.replace(/\s+/g, "-").toLowerCase();
      event.startMin = timeToMinutes(event.start);
      event.endMin = timeToMinutes(event.end);
    });
  });
}
addIds();

function overlapMinutes(a, b) {
  return Math.max(0, Math.min(a.endMin, b.endMin) - Math.max(a.startMin, b.startMin));
}

function getOverlapSeverityMap(events) {
  const severityMap = new Map();

  for (let i = 0; i < events.length; i += 1) {
    for (let j = i + 1; j < events.length; j += 1) {
      const overlap = overlapMinutes(events[i], events[j]);
      if (!overlap) continue;

      const severity = overlap <= 30 ? "yellow" : "red";
      [events[i], events[j]].forEach((event) => {
        const current = severityMap.get(event.id);
        if (current !== "red") severityMap.set(event.id, severity);
      });
    }
  }

  return severityMap;
}

function getChoiceMomentGroups(events) {
  const sorted = [...events].sort((a, b) => a.startMin - b.startMin || a.endMin - b.endMin);
  const adjacency = new Map(sorted.map((event) => [event.id, new Set()]));

  for (let i = 0; i < sorted.length; i += 1) {
    for (let j = i + 1; j < sorted.length; j += 1) {
      const overlap = overlapMinutes(sorted[i], sorted[j]);
      if (overlap > 30) {
        adjacency.get(sorted[i].id).add(sorted[j].id);
        adjacency.get(sorted[j].id).add(sorted[i].id);
      }
    }
  }

  const eventById = new Map(sorted.map((event) => [event.id, event]));
  const seen = new Set();
  const groups = [];

  sorted.forEach((event) => {
    if (seen.has(event.id) || adjacency.get(event.id).size === 0) return;

    const stack = [event.id];
    const group = [];
    seen.add(event.id);

    while (stack.length) {
      const id = stack.pop();
      group.push(eventById.get(id));

      adjacency.get(id).forEach((nextId) => {
        if (!seen.has(nextId)) {
          seen.add(nextId);
          stack.push(nextId);
        }
      });
    }

    groups.push(group.sort((a, b) => a.startMin - b.startMin));
  });

  return groups.sort((a, b) => Math.min(...a.map((event) => event.startMin)) - Math.min(...b.map((event) => event.startMin)));
}

function unionMinutes(events) {
  const sorted = [...events].sort((a, b) => a.startMin - b.startMin);
  let total = 0;
  let start = null;
  let end = null;

  sorted.forEach((event) => {
    if (start === null) {
      start = event.startMin;
      end = event.endMin;
    } else if (event.startMin <= end) {
      end = Math.max(end, event.endMin);
    } else {
      total += end - start;
      start = event.startMin;
      end = event.endMin;
    }
  });

  if (start !== null) total += end - start;
  return total;
}

function formatHours(minutes) {
  const hours = Math.floor(minutes / 60);
  const mins = minutes % 60;
  if (!hours) return `${mins} min`;
  if (!mins) return `${hours} uur`;
  return `${hours}u ${mins}m`;
}

function buildClipboardText(events, day) {
  if (!events.length) return "";
  return [
    `Mijn blokkenschema — ${day.label} ${day.date}`,
    ...events
      .sort((a, b) => a.startMin - b.startMin)
      .map((event) => `${event.start}–${event.end} · ${event.title} · ${event.stage}${event.note ? ` · ${event.note}` : ""}`),
  ].join("\n");
}

function EventCard({ event, top, height, selected, overlapSeverity, muted, onToggle }) {
  return (
    <button
      type="button"
      onClick={() => onToggle(event.id)}
      title={`${event.start}–${event.end} · ${event.title}`}
      className={[
        "absolute left-0.5 right-0.5 overflow-hidden rounded-lg border p-1 text-left transition-all duration-150 md:left-1 md:right-1 md:rounded-2xl md:p-2",
        "hover:-translate-y-0.5 hover:shadow-lg focus:outline-none focus:ring-2 focus:ring-neutral-900",
        selected
          ? overlapSeverity === "red"
            ? "border-rose-500 bg-rose-100 shadow-md ring-2 ring-rose-400"
            : overlapSeverity === "yellow"
              ? "border-amber-400 bg-amber-100 shadow-md ring-2 ring-amber-300"
              : "border-neutral-900 bg-neutral-950 text-white shadow-lg ring-2 ring-neutral-900"
          : "border-cyan-200 bg-cyan-50/95 text-neutral-950 shadow-sm",
        muted ? "opacity-20" : "opacity-100",
      ].join(" ")}
      style={{ top, height }}
    >
      <div className="text-[7px] font-black uppercase leading-none tracking-tight opacity-80 md:text-[10px]">
        {event.start} – {event.end}
      </div>
      <div className="mt-0.5 text-[8px] font-black uppercase leading-none tracking-tighter md:mt-1 md:text-sm md:leading-tight md:tracking-tight">{event.title}</div>
      {event.note && <div className="mt-0.5 text-[7px] font-bold uppercase leading-none opacity-75 md:mt-1 md:text-[10px] md:leading-tight">{event.note}</div>}
    </button>
  );
}

export default function UpcloseBlockPlanner() {
  const [dayKey, setDayKey] = useState("saturday");
  const [selectedIds, setSelectedIds] = useState([]);
  const [query, setQuery] = useState("");
  const [stageFilter, setStageFilter] = useState("all");
  const [onlySelected, setOnlySelected] = useState(false);
  const [copyState, setCopyState] = useState("Kopieer planning");

  useEffect(() => {
    try {
      const saved = JSON.parse(localStorage.getItem("upclose-personal-blocks") || "[]");
      if (Array.isArray(saved)) setSelectedIds(saved);
    } catch {
      setSelectedIds([]);
    }
  }, []);

  useEffect(() => {
    try {
      localStorage.setItem("upclose-personal-blocks", JSON.stringify(selectedIds));
    } catch {
      // Ignore storage errors in preview/sandboxed environments.
    }
  }, [selectedIds]);

  const day = DATA[dayKey];
  const dayStart = timeToMinutes(day.start);
  const dayEnd = timeToMinutes(day.end);
  const timelineHeight = (dayEnd - dayStart) * PX_PER_MINUTE;

  const selectedDayEvents = useMemo(
    () => day.events.filter((event) => selectedIds.includes(event.id)).sort((a, b) => a.startMin - b.startMin),
    [day.events, selectedIds]
  );

  const choiceMomentGroups = useMemo(() => getChoiceMomentGroups(selectedDayEvents), [selectedDayEvents]);
  const overlapSeverityMap = useMemo(() => getOverlapSeverityMap(selectedDayEvents), [selectedDayEvents]);

  const filteredEvents = useMemo(() => {
    const q = query.trim().toLowerCase();
    return day.events.filter((event) => {
      const matchesQuery = !q || `${event.title} ${event.stage} ${event.note || ""}`.toLowerCase().includes(q);
      const matchesStage = stageFilter === "all" || event.stage === stageFilter;
      const matchesSelected = !onlySelected || selectedIds.includes(event.id);
      return matchesQuery && matchesStage && matchesSelected;
    });
  }, [day.events, query, stageFilter, onlySelected, selectedIds]);

  const filteredIds = useMemo(() => new Set(filteredEvents.map((event) => event.id)), [filteredEvents]);


  const timeMarkers = useMemo(() => {
    const markers = [];
    for (let t = dayStart; t <= dayEnd; t += 30) markers.push(t);
    return markers;
  }, [dayStart, dayEnd]);

  const toggleEvent = (id) => {
    setSelectedIds((current) => (current.includes(id) ? current.filter((eventId) => eventId !== id) : [...current, id]));
  };

  const clearDay = () => {
    const dayIds = new Set(day.events.map((event) => event.id));
    setSelectedIds((current) => current.filter((id) => !dayIds.has(id)));
  };

  const copyPlanning = async () => {
    const text = buildClipboardText(selectedDayEvents, day);
    if (!text) return;
    try {
      await navigator.clipboard.writeText(text);
      setCopyState("Gekopieerd");
      setTimeout(() => setCopyState("Kopieer planning"), 1400);
    } catch {
      setCopyState("Kopiëren lukt niet");
      setTimeout(() => setCopyState("Kopieer planning"), 1400);
    }
  };

  const selectedMinutes = unionMinutes(selectedDayEvents);
  const fullDayMinutes = dayEnd - dayStart;

  return (
    <div className="min-h-screen bg-gradient-to-br from-cyan-200 via-cyan-100 to-sky-300 p-3 pb-24 text-neutral-950 md:p-8 md:pb-8">
      <div className="mx-auto max-w-7xl">
        <header className="mb-6 rounded-[2rem] border border-white/60 bg-white/55 p-5 shadow-xl backdrop-blur md:p-7">
          <div className="flex flex-col gap-5 md:flex-row md:items-end md:justify-between">
            <div>
              <p className="text-xs font-black uppercase tracking-[0.35em] text-neutral-600">Upclose personal planner</p>
              <h1 className="mt-2 text-4xl font-black uppercase leading-none tracking-tighter md:text-7xl">Blokkenschema</h1>
              <p className="mt-3 max-w-2xl text-sm font-medium text-neutral-700 md:text-base">
                Klik acts aan om je eigen route te maken. Alleen overlap van meer dan 30 minuten wordt een keuzemoment in de vergelijker. Kortere overlap markeren we geel in je schema.
              </p>
            </div>
            <div className="grid grid-cols-2 gap-2 rounded-3xl bg-white/70 p-2 shadow-inner">
              {Object.entries(DATA).map(([key, item]) => (
                <button
                  key={key}
                  type="button"
                  onClick={() => setDayKey(key)}
                  className={[
                    "rounded-2xl px-4 py-3 text-left transition",
                    key === dayKey ? "bg-neutral-950 text-white shadow-lg" : "bg-transparent hover:bg-white",
                  ].join(" ")}
                >
                  <div className="text-xs font-black uppercase opacity-70">{item.date}</div>
                  <div className="text-lg font-black uppercase leading-none">{item.label}</div>
                </button>
              ))}
            </div>
          </div>

          <div className="mt-6 grid gap-3 md:grid-cols-[1.4fr_0.9fr_0.9fr_auto]">
            <label className="block">
              <span className="mb-1 block text-xs font-black uppercase tracking-wider text-neutral-600">Zoeken</span>
              <input
                value={query}
                onChange={(event) => setQuery(event.target.value)}
                placeholder="Zoek act, area of settype…"
                className="w-full rounded-2xl border border-white/80 bg-white/80 px-4 py-3 font-semibold outline-none ring-neutral-950/0 transition placeholder:text-neutral-400 focus:ring-2"
              />
            </label>
            <label className="block">
              <span className="mb-1 block text-xs font-black uppercase tracking-wider text-neutral-600">Area</span>
              <select
                value={stageFilter}
                onChange={(event) => setStageFilter(event.target.value)}
                className="w-full rounded-2xl border border-white/80 bg-white/80 px-4 py-3 font-semibold outline-none focus:ring-2 focus:ring-neutral-950"
              >
                <option value="all">Alle areas</option>
                {day.stages.map((stage) => (
                  <option key={stage} value={stage}>
                    {stage}
                  </option>
                ))}
              </select>
            </label>
            <label className="flex items-end">
              <button
                type="button"
                onClick={() => setOnlySelected((current) => !current)}
                className={[
                  "w-full rounded-2xl border px-4 py-3 text-sm font-black uppercase transition",
                  onlySelected ? "border-neutral-950 bg-neutral-950 text-white" : "border-white/80 bg-white/80 hover:bg-white",
                ].join(" ")}
              >
                {onlySelected ? "Toon alles" : "Alleen mijn schema"}
              </button>
            </label>
            <div className="grid grid-cols-2 gap-2 md:flex md:items-end">
              <button
                type="button"
                onClick={copyPlanning}
                disabled={!selectedDayEvents.length}
                className="w-full rounded-2xl bg-white/80 px-4 py-3 text-sm font-black uppercase shadow-sm transition hover:bg-white disabled:cursor-not-allowed disabled:opacity-40"
              >
                {copyState}
              </button>
              <button
                type="button"
                onClick={clearDay}
                disabled={!selectedDayEvents.length}
                className="w-full rounded-2xl bg-white/50 px-4 py-3 text-sm font-black uppercase transition hover:bg-white disabled:cursor-not-allowed disabled:opacity-40"
              >
                Wis dag
              </button>
            </div>
          </div>
        </header>

        <section className="mb-5 grid grid-cols-2 gap-3 md:grid-cols-4">
          <div className="rounded-3xl bg-white/70 p-4 shadow-sm backdrop-blur">
            <div className="text-xs font-black uppercase tracking-wider text-neutral-500">Geselecteerd</div>
            <div className="mt-1 text-2xl font-black md:text-3xl">{selectedDayEvents.length}</div>
          </div>
          <div className="rounded-3xl bg-white/70 p-4 shadow-sm backdrop-blur">
            <div className="text-xs font-black uppercase tracking-wider text-neutral-500">Unieke kijktijd</div>
            <div className="mt-1 text-2xl font-black md:text-3xl">{formatHours(selectedMinutes)}</div>
          </div>
          <div className="rounded-3xl bg-white/70 p-4 shadow-sm backdrop-blur">
            <div className="text-xs font-black uppercase tracking-wider text-neutral-500">Keuzemomenten</div>
            <div className="mt-1 text-2xl font-black md:text-3xl">{choiceMomentGroups.length}</div>
          </div>
          <div className="rounded-3xl bg-white/70 p-4 shadow-sm backdrop-blur">
            <div className="text-xs font-black uppercase tracking-wider text-neutral-500">Dag gevuld</div>
            <div className="mt-1 text-2xl font-black md:text-3xl">{Math.round((selectedMinutes / fullDayMinutes) * 100)}%</div>
          </div>
        </section>

        <main className="grid gap-6 xl:grid-cols-[minmax(0,1fr)_390px]">
          <section className="overflow-hidden rounded-[2rem] border border-white/60 bg-white/45 shadow-xl backdrop-blur">
            <div className="flex items-center justify-between gap-3 border-b border-white/60 p-4">
              <div>
                <h2 className="text-xl font-black uppercase tracking-tight">{day.label} {day.date}</h2>
                <p className="text-xs font-bold uppercase text-neutral-600">Klik blokken aan om toe te voegen of te verwijderen. Op mobiel blijft de timetable naast elkaar staan.</p>
              </div>
              <div className="rounded-full bg-white/80 px-3 py-1 text-xs font-black uppercase">{day.start}–{day.end}</div>
            </div>

            <div className="overflow-x-hidden p-1.5 md:p-3">
              <div className="min-w-0">
                <div className="grid grid-cols-[34px_repeat(6,minmax(0,1fr))] gap-0.5 md:grid-cols-[56px_repeat(6,minmax(80px,1fr))] md:gap-1 lg:grid-cols-[72px_repeat(6,minmax(140px,1fr))]">
                  <div />
                  {day.stages.map((stage) => (
                    <div key={stage} className="rounded-t-lg bg-white/80 py-2 text-center text-[8px] font-black uppercase tracking-tight md:rounded-t-2xl md:py-3 md:text-sm md:tracking-[0.25em]">
                      {stage}
                    </div>
                  ))}
                </div>

                <div className="grid grid-cols-[34px_repeat(6,minmax(0,1fr))] gap-0.5 md:grid-cols-[56px_repeat(6,minmax(80px,1fr))] md:gap-1 lg:grid-cols-[72px_repeat(6,minmax(140px,1fr))]">
                  <div className="relative" style={{ height: timelineHeight }}>
                    {timeMarkers.map((marker) => (
                      <div
                        key={marker}
                        className="absolute left-0 right-0 -translate-y-1/2 pr-0.5 text-right text-[8px] font-black tabular-nums text-neutral-700 md:pr-2 md:text-sm"
                        style={{ top: (marker - dayStart) * PX_PER_MINUTE }}
                      >
                        {minutesToTime(marker)}
                      </div>
                    ))}
                  </div>

                  {day.stages.map((stage) => (
                    <div key={stage} className="relative rounded-b-lg bg-white/45 md:rounded-b-2xl" style={{ height: timelineHeight }}>
                      {timeMarkers.map((marker) => (
                        <div
                          key={`${stage}-${marker}`}
                          className={marker % 60 === 0 ? "absolute left-0 right-0 border-t border-white/80" : "absolute left-0 right-0 border-t border-white/35"}
                          style={{ top: (marker - dayStart) * PX_PER_MINUTE }}
                        />
                      ))}
                      {day.events
                        .filter((event) => event.stage === stage)
                        .map((event) => {
                          const selected = selectedIds.includes(event.id);
                          const muted = !filteredIds.has(event.id);
                          return (
                            <EventCard
                              key={event.id}
                              event={event}
                              selected={selected}
                              overlapSeverity={selected ? overlapSeverityMap.get(event.id) : null}
                              muted={muted}
                              top={(event.startMin - dayStart) * PX_PER_MINUTE + 2}
                              height={Math.max((event.endMin - event.startMin) * PX_PER_MINUTE - 4, 42)}
                              onToggle={toggleEvent}
                            />
                          );
                        })}
                    </div>
                  ))}
                </div>
              </div>
            </div>
          </section>

          <aside className="space-y-4">
            <section className="rounded-[2rem] border border-white/60 bg-white/70 p-4 shadow-xl backdrop-blur">
              <div className="mb-3 flex items-center justify-between gap-2">
                <div>
                  <h2 className="text-xl font-black uppercase tracking-tight">Mijn schema</h2>
                  <p className="text-xs font-bold uppercase text-neutral-600">Gesorteerd op tijd</p>
                </div>
                <span className="rounded-full bg-neutral-950 px-3 py-1 text-xs font-black text-white">{selectedDayEvents.length}</span>
              </div>

              {!selectedDayEvents.length ? (
                <div className="rounded-3xl border border-dashed border-neutral-300 bg-white/50 p-5 text-sm font-semibold text-neutral-600">
                  Nog geen acts geselecteerd. Klik links op de blokken die je wil zien.
                </div>
              ) : (
                <div className="space-y-2">
                  {selectedDayEvents.map((event) => (
                    <button
                      key={event.id}
                      type="button"
                      onClick={() => toggleEvent(event.id)}
                      className={[
                        "w-full rounded-3xl border p-3 text-left transition hover:-translate-y-0.5 hover:shadow-md",
                        overlapSeverityMap.get(event.id) === "red"
                          ? "border-rose-300 bg-rose-50"
                          : overlapSeverityMap.get(event.id) === "yellow"
                            ? "border-amber-300 bg-amber-50"
                            : "border-white bg-white/80",
                      ].join(" ")}
                    >
                      <div className="flex items-start justify-between gap-3">
                        <div>
                          <div className="text-xs font-black uppercase text-neutral-500">{event.start} – {event.end} · {event.stage}</div>
                          <div className="mt-1 text-base font-black uppercase leading-tight">{event.title}</div>
                          {event.note && <div className="mt-1 text-xs font-bold uppercase text-neutral-500">{event.note}</div>}
                        </div>
                        <span className="shrink-0 rounded-full bg-neutral-950 px-2 py-1 text-[10px] font-black uppercase text-white">Verwijder</span>
                      </div>
                    </button>
                  ))}
                </div>
              )}
            </section>

            <section className="rounded-[2rem] border border-white/60 bg-white/70 p-4 shadow-xl backdrop-blur">
              <h2 className="text-xl font-black uppercase tracking-tight">Vergelijker</h2>
              <p className="mt-1 text-xs font-bold uppercase text-neutral-600">
                Alleen overlap van meer dan 30 minuten komt hier als keuzemoment te staan.
              </p>

              {!choiceMomentGroups.length ? (
                <div className="mt-4 rounded-3xl bg-emerald-50 p-4 text-sm font-bold text-emerald-900">
                  Geen overlap in je huidige selectie voor deze dag.
                </div>
              ) : (
                <div className="mt-4 space-y-3">
                  {choiceMomentGroups.map((group, index) => {
                    const start = Math.min(...group.map((event) => event.startMin));
                    const end = Math.max(...group.map((event) => event.endMin));
                    return (
                      <div key={`${index}-${start}`} className="rounded-3xl border border-rose-200 bg-rose-50 p-3">
                        <div className="mb-2 text-xs font-black uppercase text-rose-900">
                          Keuzemoment {index + 1} · {minutesToTime(start)}–{minutesToTime(end)} · meer dan 30 min overlap
                        </div>
                        <div className="grid gap-2 sm:grid-cols-2 lg:grid-cols-3">
                          {group.map((event) => (
                            <button
                              key={event.id}
                              type="button"
                              onClick={() => toggleEvent(event.id)}
                              className="rounded-2xl bg-white p-3 text-left shadow-sm transition hover:shadow-md"
                            >
                              <div className="text-[10px] font-black uppercase text-neutral-500">{event.start}–{event.end}</div>
                              <div className="mt-1 text-sm font-black uppercase leading-tight">{event.title}</div>
                              <div className="mt-2 text-[10px] font-black uppercase text-neutral-500">{event.stage}</div>
                            </button>
                          ))}
                        </div>
                      </div>
                    );
                  })}
                </div>
              )}
            </section>

            <section className="rounded-[2rem] border border-white/60 bg-white/70 p-4 shadow-xl backdrop-blur">
              <h2 className="text-xl font-black uppercase tracking-tight">Tips</h2>
              <div className="mt-3 space-y-2 text-sm font-semibold text-neutral-700">
                <p>• Zwarte blokken zitten in je persoonlijke schema.</p>
                <p>• Gele blokken overlappen maximaal 30 minuten.</p>
                <p>• Roze blokken overlappen meer dan 30 minuten en komen in de vergelijker.</p>
                <p>• Gebruik zoeken om snel een artiest of area te vinden.</p>
                <p>• Je selectie wordt lokaal opgeslagen in je browser.</p>
              </div>
            </section>
          </aside>
        </main>

        <div className="fixed inset-x-3 bottom-3 z-50 rounded-3xl border border-white/70 bg-white/85 p-3 shadow-2xl backdrop-blur lg:hidden">
          <div className="flex items-center justify-between gap-3">
            <div>
              <div className="text-[10px] font-black uppercase tracking-wider text-neutral-500">Mijn schema</div>
              <div className="text-base font-black uppercase leading-tight">
                {selectedDayEvents.length} acts · {choiceMomentGroups.length} keuzemomenten
              </div>
            </div>
            <button
              type="button"
              onClick={() => setOnlySelected((current) => !current)}
              className="shrink-0 rounded-2xl bg-neutral-950 px-4 py-3 text-xs font-black uppercase text-white"
            >
              {onlySelected ? "Alles" : "Mijn"}
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}