// Path in project: app/admin/schedule/set-schedule-page.tsx (or wherever the original lives)
"use client";
import { useSearchParams } from "next/navigation";

import { useEffect, useMemo, useState } from "react";
import axiosInstance from "@/lib/axiosInstance";
import { WEEKDAYS, fmt12 } from "@/lib/timeslot-utils";
import Link from "next/link";

interface Student { id: number; name: string; student_id: string; }
interface SlotOption { start_time: string; end_time: string; capacity: number; booked_count: number; }
interface WeekdayGroup { weekday: number; slots: SlotOption[]; }

interface BookingWithTime {
  id: number;
  time_slot_id: number;
  booking_date: string;
  time_slots: { start_time: string; end_time: string };
}
interface Pattern { weekday: number; start_time: string; end_time: string; }
interface ExistingSchedule {
  id: number;
  start_date: string;
  end_date: string;
  status: string;
  student_schedule_patterns: Pattern[];
  schedule_bookings: BookingWithTime[];
}

interface MasterRecord {
  id: number;
  start_date: string;
  end_date: string;
}

interface GeneratedSlot {
  id: number;
  slot_date: string;
  start_time: string;
  end_time: string;
  capacity: number;
  booked_count: number;
}

type Mode = "weekday" | "date";

// ---- shared, stateless calendar-grid builder (used by both calendars on this page) ----
function buildCalendarCells(month: Date) {
  const year = month.getFullYear();
  const m = month.getMonth();
  const firstDayOfMonth = new Date(year, m, 1);
  const daysInMonth = new Date(year, m + 1, 0).getDate();
  const leadingBlanks = firstDayOfMonth.getDay();

  const cells: { dateKey: string | null; dayNumber: number | null }[] = [];
  for (let i = 0; i < leadingBlanks; i++) cells.push({ dateKey: null, dayNumber: null });
  for (let d = 1; d <= daysInMonth; d++) {
    const dateKey = `${year}-${String(m + 1).padStart(2, "0")}-${String(d).padStart(2, "0")}`;
    cells.push({ dateKey, dayNumber: d });
  }
  return cells;
}

function enumerateDates(start: string, end: string): string[] {
  const out: string[] = [];
  const cursor = new Date(start + "T00:00:00Z");
  const endD = new Date(end + "T00:00:00Z");
  while (cursor.getTime() <= endD.getTime()) {
    out.push(cursor.toISOString().slice(0, 10));
    cursor.setUTCDate(cursor.getUTCDate() + 1);
  }
  return out;
}

function addOneDay(dateKey: string): string {
  const d = new Date(dateKey + "T00:00:00Z");
  d.setUTCDate(d.getUTCDate() + 1);
  return d.toISOString().slice(0, 10);
}

// Local "today" as YYYY-MM-DD, used for all past-date comparisons on this page.
function getTodayKey() {
  const now = new Date();
  const year = now.getFullYear();
  const month = String(now.getMonth() + 1).padStart(2, "0");
  const day = String(now.getDate()).padStart(2, "0");
  return `${year}-${month}-${day}`;
}

// Masters are often generated in separate adjacent batches (e.g. week by week).
// "One continuous master" means no gap between batches — so merge any
// overlapping/adjacent master records into continuous segments before checking
// whether a selected range fits inside one of them.
function mergeMasterRanges(masters: { start_date: string; end_date: string }[]) {
  const sorted = masters
    .map((m) => ({ start: m.start_date.slice(0, 10), end: m.end_date.slice(0, 10) }))
    .sort((a, b) => (a.start < b.start ? -1 : a.start > b.start ? 1 : 0));

  const merged: { start: string; end: string }[] = [];
  for (const r of sorted) {
    const last = merged[merged.length - 1];
    if (last && r.start <= addOneDay(last.end)) {
      if (r.end > last.end) last.end = r.end;
    } else {
      merged.push({ start: r.start, end: r.end });
    }
  }
  return merged;
}


export default function SetSchedulePage() {
  const [mode, setMode] = useState<Mode>("weekday");

  const [students, setStudents] = useState<Student[]>([]);
  const [studentId, setStudentId] = useState<string>("");
  const [existingSchedules, setExistingSchedules] = useState<ExistingSchedule[]>([]);
  const [masters, setMasters] = useState<MasterRecord[]>([]);
  const [overallRange, setOverallRange] = useState<{ start: string; end: string } | null>(null);

  const [statusMsg, setStatusMsg] = useState<string | null>(null);
  const [statusIsError, setStatusIsError] = useState(false);

  // Every generated slot date, loaded once, drives the calendar highlighting in both modes
  const [slotsByDate, setSlotsByDate] = useState<Record<string, GeneratedSlot[]>>({});
  const [calendarLoading, setCalendarLoading] = useState(false);
  const [visibleMonth, setVisibleMonth] = useState(() => {
    const now = new Date();
    return new Date(now.getFullYear(), now.getMonth(), 1);
  });

  const todayKey = useMemo(() => getTodayKey(), []);
  const isPastDate = (dateKey: string) => dateKey < todayKey;

  // --- weekday mode state ---
  const [startDate, setStartDate] = useState("");
  const [endDate, setEndDate] = useState("");
  const [groups, setGroups] = useState<WeekdayGroup[]>([]);
  const [selection, setSelection] = useState<Record<number, SlotOption>>({});
  const [rangeError, setRangeError] = useState<string | null>(null);
  const [rangeNote, setRangeNote] = useState<string | null>(null);

  // --- specific date mode state ---
  // dateRangeStart/dateRangeEnd are now the actual assignment selection (not a "viewing window").
  // A single click = single-date assignment. Two clicks = a range, loaded date-wise below.
  const [dateRangeStart, setDateRangeStart] = useState("");
  const [dateRangeEnd, setDateRangeEnd] = useState("");
  const [dateModeError, setDateModeError] = useState<string | null>(null);
  const [perDateSlots, setPerDateSlots] = useState<Record<string, GeneratedSlot[]>>({});
  const [perDateSelection, setPerDateSelection] = useState<Record<string, GeneratedSlot>>({});
  const [dateSlotsLoaded, setDateSlotsLoaded] = useState(false);

  // --- assigned-slots calendar (view + change slot for a specific date) ---
  const [assignedMonth, setAssignedMonth] = useState(() => new Date());
  const [changeDate, setChangeDate] = useState<string | null>(null);
  const [changeDateSlot, setChangeDateSlot] = useState<GeneratedSlot | null>(null);
  const searchParams = useSearchParams();


  const [findSlotsLoading, setFindSlotsLoading] = useState(false);
  const [submitWeekdayLoading, setSubmitWeekdayLoading] = useState(false);
  const [loadDateSlotsLoading, setLoadDateSlotsLoading] = useState(false);
  const [assignDatesLoading, setAssignDatesLoading] = useState(false);
  const [changeSlotLoading, setChangeSlotLoading] = useState(false);

  // Per-id loading flags for cancel/delete actions, e.g. { "schedule-12": true, "booking-45": true }
  const [cancelLoading, setCancelLoading] = useState<Record<string, boolean>>({});
  const setCancelKeyLoading = (key: string, val: boolean) =>
    setCancelLoading((prev) => ({ ...prev, [key]: val }));

  useEffect(() => {
    if (!statusMsg) return;
    const timer = setTimeout(() => setStatusMsg(null), 2000);
    return () => clearTimeout(timer);
  }, [statusMsg]);

  useEffect(() => {
    const selectedStudentId = searchParams.get("studentId");
    if (selectedStudentId) {
      setStudentId(selectedStudentId);
    }
  }, [searchParams]);
  useEffect(() => {
    axiosInstance.get("/admin/students").then((res) => setStudents(res.data.data));
    loadMastersAndSlots();
  }, []);

  const loadMastersAndSlots = async () => {
    setCalendarLoading(true);
    try {
      const mastersRes = await axiosInstance.get("/admin/timeslots/masters");
      const masterList: MasterRecord[] = mastersRes.data.data;
      setMasters(masterList);

      if (!masterList.length) {
        setSlotsByDate({});
        setOverallRange(null);
        return;
      }

      const earliestStart = masterList.reduce((min, m) => (m.start_date < min ? m.start_date : min), masterList[0].start_date);
      const latestEnd = masterList.reduce((max, m) => (m.end_date > max ? m.end_date : max), masterList[0].end_date);
      setOverallRange({ start: earliestStart.slice(0, 10), end: latestEnd.slice(0, 10) });

      const rangeRes = await axiosInstance.get(
        `/admin/timeslots/range?start_date=${earliestStart.slice(0, 10)}&end_date=${latestEnd.slice(0, 10)}`
      );
      const slots: GeneratedSlot[] = rangeRes.data.data;

      const grouped: Record<string, GeneratedSlot[]> = {};
      for (const slot of slots) {
        const dateKey = slot.slot_date.slice(0, 10);
        if (!grouped[dateKey]) grouped[dateKey] = [];
        grouped[dateKey].push(slot);
      }
      setSlotsByDate(grouped);
      setVisibleMonth(new Date(new Date(earliestStart).getUTCFullYear(), new Date(earliestStart).getUTCMonth(), 1));
    } finally {
      setCalendarLoading(false);
    }
  };

  const refreshExistingSchedules = async (sid: string) => {
    if (!sid) {
      setExistingSchedules([]);
      return;
    }
    const res = await axiosInstance.get(`/admin/schedules?student_id=${sid}`);
    setExistingSchedules(res.data.data);
  };

  useEffect(() => {
    refreshExistingSchedules(studentId);
  }, [studentId]);

  const switchMode = (next: Mode) => {
    setMode(next);
    setStatusMsg(null);
    setGroups([]);
    setSelection({});
    setRangeError(null);
    setRangeNote(null);
    setStartDate("");
    setEndDate("");
    setDateRangeStart("");
    setDateRangeEnd("");
    setDateModeError(null);
    setPerDateSlots({});
    setPerDateSelection({});
    setDateSlotsLoaded(false);
  };

  // Merge adjacent/overlapping master batches into continuous segments, then a
  // selected range is valid if it fits entirely inside one such segment — i.e.
  // it doesn't straddle an actual gap between two non-adjacent batches.
  const mergedMasterRanges = useMemo(() => mergeMasterRanges(masters), [masters]);

  const findContainingMaster = (start: string, end: string) =>
    mergedMasterRanges.find((seg) => seg.start <= start && seg.end >= end) || null;

  const slotsExistText = overallRange ? `Slots exist from ${overallRange.start} to ${overallRange.end}.` : null;
  const masterHintText = overallRange
    ? `Slots exist from ${overallRange.start} to ${overallRange.end}. Your range must fall within one continuous master.`
    : null;

  // ---------- MAIN CALENDAR (weekday range picking / specific-date picking) ----------
  const calendarCells = useMemo(() => buildCalendarCells(visibleMonth), [visibleMonth]);
  const monthLabel = visibleMonth.toLocaleDateString(undefined, { month: "long", year: "numeric" });
  const goPrevMonth = () => setVisibleMonth((m) => new Date(m.getFullYear(), m.getMonth() - 1, 1));
  const goNextMonth = () => setVisibleMonth((m) => new Date(m.getFullYear(), m.getMonth() + 1, 1));

  const handleCalendarClick = (dateKey: string) => {
    if (!slotsByDate[dateKey]) return; // no slots this day — not clickable
    if (isPastDate(dateKey)) return; // past date — not clickable for new assignments

    if (mode === "date") {
      if (!dateRangeStart || (dateRangeStart && dateRangeEnd)) {
        setDateRangeStart(dateKey);
        setDateRangeEnd("");
      } else if (dateKey < dateRangeStart) {
        setDateRangeStart(dateKey);
      } else {
        setDateRangeEnd(dateKey);
      }
      setPerDateSlots({});
      setPerDateSelection({});
      setDateSlotsLoaded(false);
      setDateModeError(null);
      return;
    }

    // weekday mode: first click sets start, second click sets end
    if (!startDate || (startDate && endDate)) {
      setStartDate(dateKey);
      setEndDate("");
      setGroups([]);
      setRangeError(null);
      setRangeNote(null);
    } else if (dateKey < startDate) {
      setStartDate(dateKey);
    } else {
      setEndDate(dateKey);
    }
  };

  // ---------- WEEKDAY MODE ----------
  const getWeekdayConflict = (weekday: number) => {
    for (const sched of existingSchedules) {
      if (sched.status !== "active") continue;
      const overlapsRange = sched.start_date.slice(0, 10) <= endDate && sched.end_date.slice(0, 10) >= startDate;
      if (!overlapsRange) continue;
      const pattern = sched.student_schedule_patterns.find((p) => p.weekday === weekday);
      if (pattern) return { schedule: sched, pattern };
    }
    return null;
  };

  const findSlots = async () => {
    setRangeError(null);
    setRangeNote(null);
    setGroups([]);
    setStatusMsg(null);

    if (!studentId) {
      setRangeError("Select a student first.");
      return;
    }
    if (!startDate || !endDate) {
      setRangeError("Click a start date and an end date on the calendar.");
      return;
    }

    setFindSlotsLoading(true);
    try {
      const { data } = await axiosInstance.get(`/admin/schedules/available-slots?start_date=${startDate}&end_date=${endDate}`);
      const result: WeekdayGroup[] = data.data;

      if (!result.length) {
        setRangeError("No slots exist anywhere in this range.");
        return;
      }

      const datesWithGaps = hasGapsInRange(startDate, endDate);
      if (datesWithGaps) {
        setRangeNote("Some dates in this range have no slots and will be skipped automatically.");
      }

      setGroups(result);
      setSelection({});
    } finally {
      setFindSlotsLoading(false);
    }
  };

  const hasGapsInRange = (start: string, end: string): boolean =>
    enumerateDates(start, end).some((key) => !slotsByDate[key]);

  const pickSlot = (weekday: number, slot: SlotOption) => {
    setSelection((prev) => ({ ...prev, [weekday]: slot }));
  };

  const cancelSchedule = async (scheduleId: number) => {
    if (!confirm("Cancel this entire recurring assignment? All future dates under it will be freed up.")) return;
    const key = `schedule-${scheduleId}`;
    setCancelKeyLoading(key, true);
    try {
      await axiosInstance.delete(`/admin/schedules/${scheduleId}`);
      setStatusIsError(false);
      setStatusMsg("Assignment cancelled.");
      await refreshExistingSchedules(studentId);
    } catch (err: any) {
      setStatusIsError(true);
      setStatusMsg(err?.response?.data?.error ?? "Failed to cancel assignment.");
    } finally {
      setCancelKeyLoading(key, false);
    }
  };

  const submitWeekdaySchedule = async () => {
    const patterns = Object.entries(selection).map(([weekday, slot]) => ({
      weekday: Number(weekday),
      start_time: slot.start_time,
      end_time: slot.end_time,
    }));

    if (!studentId || patterns.length === 0) {
      setStatusIsError(true);
      setStatusMsg("Select a student and at least one time slot.");
      return;
    }

    setSubmitWeekdayLoading(true);
    try {
      await axiosInstance.post("/admin/schedules", {
        student_id: Number(studentId),
        start_date: startDate,
        end_date: endDate,
        patterns,
      });
      setStatusIsError(false);
      setStatusMsg("Schedule created successfully. Dates without slots in this range were skipped automatically.");
      setGroups([]);
      setSelection({});
      await refreshExistingSchedules(studentId);
    } catch (err: any) {
      setStatusIsError(true);
      setStatusMsg(err?.response?.data?.error ?? "Failed to create schedule.");
    } finally {
      setSubmitWeekdayLoading(false);
    }
  };



  // ---------- SPECIFIC DATE MODE ----------
  const getExistingBookingForDate = (dateKey: string) => {
    for (const sched of existingSchedules) {
      const match = sched.schedule_bookings.find((b) => b.booking_date.slice(0, 10) === dateKey);
      if (match) return { schedule: sched, booking: match };
    }
    return null;
  };

  const loadDateSlots = async () => {
    setStatusMsg(null);
    setDateModeError(null);
    if (!studentId) {
      setStatusIsError(true);
      setStatusMsg("Select a student first.");
      return;
    }
    if (!dateRangeStart) {
      setStatusIsError(true);
      setStatusMsg("Click a date (or a start and end date) on the calendar.");
      return;
    }

    setLoadDateSlotsLoading(true);
    try {
      const start = dateRangeStart;
      const end = dateRangeEnd || dateRangeStart;

      const master = findContainingMaster(start, end);
      if (!master) {
        setDateModeError(masterHintText ?? "Your selected range must fall within one continuous master.");
        return;
      }

      const dates = enumerateDates(start, end).filter((d) => slotsByDate[d]);
      if (!dates.length) {
        setDateModeError("No slots exist in this range.");
        return;
      }

      const map: Record<string, GeneratedSlot[]> = {};
      for (const d of dates) map[d] = slotsByDate[d];
      setPerDateSlots(map);
      setPerDateSelection({});
      setDateSlotsLoaded(true);
    } finally {
      setLoadDateSlotsLoading(false);
    }
  };

  const pickDateSlot = (dateKey: string, slot: GeneratedSlot) => {
    setPerDateSelection((prev) => ({ ...prev, [dateKey]: slot }));
  };

  const assignSpecificDates = async () => {
    const entries = Object.entries(perDateSelection);
    if (!studentId || entries.length === 0) {
      setStatusIsError(true);
      setStatusMsg("Select a student and at least one date's time slot.");
      return;
    }

    const dateSlotsPayload = entries.map(([date, slot]) => ({
      date,
      start_time: slot.start_time,
      end_time: slot.end_time,
    }));
    const sortedDates = entries.map(([d]) => d).sort();

    setAssignDatesLoading(true);
    try {
      await axiosInstance.post("/admin/schedules", {
        student_id: Number(studentId),
        start_date: sortedDates[0],
        end_date: sortedDates[sortedDates.length - 1],
        date_slots: dateSlotsPayload,
      });
      setStatusIsError(false);
      setStatusMsg(entries.length > 1 ? "Slots assigned for selected dates." : "Slot assigned for this date.");
      setPerDateSelection({});
      setPerDateSlots({});
      setDateSlotsLoaded(false);
      setDateRangeStart("");
      setDateRangeEnd("");
      await refreshExistingSchedules(studentId);
    } catch (err: any) {
      setStatusIsError(true);
      setStatusMsg(err?.response?.data?.error ?? "Failed to assign slot(s).");
    } finally {
      setAssignDatesLoading(false);
    }
  };

  const cancelDateBooking = async (bookingId: number) => {
    if (!confirm("Cancel this date's assignment?")) return;
    const key = `booking-${bookingId}`;
    setCancelKeyLoading(key, true);
    try {
      await axiosInstance.delete(`/admin/schedules/bookings/${bookingId}`);
      setStatusIsError(false);
      setStatusMsg("Booking cancelled.");
      await refreshExistingSchedules(studentId);
    } catch (err: any) {
      setStatusIsError(true);
      setStatusMsg(err?.response?.data?.error ?? "Failed to cancel booking.");
    } finally {
      setCancelKeyLoading(key, false);
    }
  };

  // ---------- ASSIGNED SLOTS CALENDAR (view + change slot for one date) ----------
  const bookingsByDate = useMemo(() => {
    const map: Record<string, { schedule: ExistingSchedule; booking: BookingWithTime }> = {};
    for (const sched of existingSchedules) {
      if (sched.status !== "active") continue;
      for (const b of sched.schedule_bookings) {
        map[b.booking_date.slice(0, 10)] = { schedule: sched, booking: b };
      }
    }
    return map;
  }, [existingSchedules]);

  const assignedCells = useMemo(() => buildCalendarCells(assignedMonth), [assignedMonth]);
  const assignedMonthLabel = assignedMonth.toLocaleDateString(undefined, { month: "long", year: "numeric" });
  const goPrevAssignedMonth = () => setAssignedMonth((m) => new Date(m.getFullYear(), m.getMonth() - 1, 1));
  const goNextAssignedMonth = () => setAssignedMonth((m) => new Date(m.getFullYear(), m.getMonth() + 1, 1));

  const openChangeSlot = (dateKey: string) => {
    if (!bookingsByDate[dateKey]) return;
    if (isPastDate(dateKey)) return; // don't allow changing/cancelling a class that's already happened
    setChangeDate(dateKey);
    setChangeDateSlot(null);
  };

  const submitChangeSlot = async () => {
    if (!changeDate || !changeDateSlot) return;
    const current = bookingsByDate[changeDate];
    if (!current) return;

    setChangeSlotLoading(true);
    try {
      await axiosInstance.put(`/admin/schedules/bookings/${current.booking.id}`, {
        time_slot_id: changeDateSlot.id,
      });
      setStatusIsError(false);
      setStatusMsg(`Slot changed for ${changeDate}.`);
      setChangeDate(null);
      setChangeDateSlot(null);
      await refreshExistingSchedules(studentId);
    } catch (err: any) {
      setStatusIsError(true);
      setStatusMsg(err?.response?.data?.error ?? "Failed to change slot.");
    } finally {
      setChangeSlotLoading(false);
    }
  };

  return (
    <div className="admin-page-wrapper">
      <div className="admin-page-header mb-4">
        <div className="d-flex justify-content-between align-items-center">
          <div>
            <h2 className="admin-page-title">Set Student Schedule</h2>
            <p className="admin-page-subtitle">Assign a recurring weekday time slot, or assign one or more specific dates</p>
          </div>
          <div className="d-flex gap-2 flex-wrap">
            <Link href="/admin/timeslots" className="btn btn-light px-4">
              <i className="bi bi-arrow-left me-2" />
              Back to Time Slots
            </Link>
            <Link href="/admin/students" className="admin-theme-btn">
              <i className="bi bi-arrow-left me-2" /> Back to Students
            </Link>
          </div>
        </div>
      </div>

      <div className="card-theme p-4">
        <div className="row g-4 mb-2">
          <div className="col-md-6">
            <label className="form-label">Student</label>
            <select className="form-select" value={studentId} onChange={(e) => setStudentId(e.target.value)}>
              <option value="">Select a student</option>
              {students.map((s) => (
                <option key={s.id} value={s.id}>
                  {s.name} ({s.student_id})
                </option>
              ))}
            </select>
          </div>

          <div className="col-md-6">
            <label className="form-label d-block">Assignment type</label>
            <div className="btn-group w-100" role="group">
              <button
                type="button"
                className={`btn btn-sm ${mode === "weekday" ? "admin-theme-btn" : "btn-outline-secondary"}`}
                onClick={() => switchMode("weekday")}
              >
                By weekday (date range)
              </button>
              <button
                type="button"
                className={`btn btn-sm ${mode === "date" ? "admin-theme-btn" : "btn-outline-secondary"}`}
                onClick={() => switchMode("date")}
              >
                Specific date(s)
              </button>
            </div>
          </div>
        </div>

        <div className="row">
          {/* LEFT: calendar */}
          <div className="col-lg-6">
            <div className="border rounded p-3">
              <div className="d-flex calendar-control justify-content-between align-items-center mb-2">
                <button className="default-btn" onClick={goPrevMonth}>
                  <i className="bi bi-chevron-left" />
                </button>
                <span className="fw-semibold">{monthLabel}</span>
                <button className="default-btn" onClick={goNextMonth}>
                  <i className="bi bi-chevron-right" />
                </button>
              </div>

              {/* {mode === "date" ? masterHintText && <p className="text-muted small mb-2">{masterHintText}</p> : slotsExistText && <p className="text-muted small mb-2">{slotsExistText}</p>} */}

              <p className="text-muted small my-3">
                {mode === "weekday"
                  ? "Click a start date, then an end date. Only highlighted days have slots."
                  : "Click a single date to load its slots, or click a start and end date to load a range date-wise."}
              </p>

              <div className="d-grid schedule-slot" style={{ gridTemplateColumns: "repeat(7, 1fr)", gap: 4 }}>
                {WEEKDAYS.map((wd) => (
                  <div key={wd} className="text-center small fw-semibold text-muted">
                    {wd.slice(0, 2)}
                  </div>
                ))}

                {calendarCells.map((cell, idx) => {
                  if (!cell.dateKey) return <div key={idx} />;

                  const hasSlots = !!slotsByDate[cell.dateKey];
                  const past = isPastDate(cell.dateKey);
                  const clickable = hasSlots && !past;

                  const isStart = mode === "weekday" ? cell.dateKey === startDate : cell.dateKey === dateRangeStart;
                  const isEnd = mode === "weekday" ? cell.dateKey === endDate : cell.dateKey === dateRangeEnd;
                  const rangeA = mode === "weekday" ? startDate : dateRangeStart;
                  const rangeB = mode === "weekday" ? endDate : dateRangeEnd;
                  const inRange = !!rangeA && !!rangeB && cell.dateKey >= rangeA && cell.dateKey <= rangeB;

                  let btnClass = "btn-light";
                  if (!clickable) btnClass = "btn-light";
                  else if (isStart || isEnd) btnClass = "schedule-selected";
                  else if (inRange) btnClass = "schedule-btn-range";
                  else btnClass = "available-schedule";

                  return (
                    <button
                      key={idx}
                      onClick={() => handleCalendarClick(cell.dateKey!)}
                      disabled={!clickable}
                      title={past ? "This date has already passed" : undefined}
                      className={`schedule-btn ${btnClass}`}
                      style={{opacity: clickable ? 1 : hasSlots && past ? 0.3 : 0.35 }}
                    >
                      {cell.dayNumber}
                    </button>
                  );
                })}
              </div>

              <div className="mt-3">
                <button className="schedule-btn default-btn" onClick={loadMastersAndSlots} disabled={calendarLoading}>
                  {calendarLoading ? "Refreshing..." : "Refresh"}
                </button>
              </div>
            </div>
          </div>

          {/* RIGHT: mode-specific controls */}
          <div className="col-lg-6 mt-4 mt-lg-0">
            <div className="border rounded p-3 h-100">
              <div className="time-slot-wrapper">
                {mode === "weekday" && (
                  <>
                    <p className="fw-medium mb-2">
                      {startDate && endDate
                        ? `${startDate} to ${endDate}`
                        : startDate
                          ? `${startDate} — click an end date`
                          : "Pick a range on the calendar"}
                    </p>

                    {startDate && endDate && (
                      <button className="admin-theme-btn mb-3" onClick={findSlots} disabled={findSlotsLoading}>
                        {findSlotsLoading ? (
                          <><span className="spinner-border spinner-border-sm me-2" />Finding...</>
                        ) : (
                          "Find slots"
                        )}
                      </button>
                    )}

                    {rangeError && <p className="text-danger small mb-3">{rangeError}</p>}
                    {rangeNote && <p className="text-muted small mb-3">{rangeNote}</p>}

                    {groups.map((group) => {
                      const conflict = getWeekdayConflict(group.weekday);
                      const cancelling = conflict ? !!cancelLoading[`schedule-${conflict.schedule.id}`] : false;
                      return (
                        <div key={group.weekday} className="time-slot-bx">
                          <h4>{WEEKDAYS[group.weekday]}</h4>
                          {conflict && (
                            <div className="already-assign d-flex align-items-center gap-3 flex-wrap mb-2">
                              <span className="small">
                                Already assigned: {fmt12(conflict.pattern.start_time)} - {fmt12(conflict.pattern.end_time)}
                                <span> ({conflict.schedule.start_date.slice(0, 10)} to {conflict.schedule.end_date.slice(0, 10)})</span>
                              </span>
                              {/* <button
                                className="btn btn-sm btn-outline-danger ms-auto"
                                disabled={cancelling}
                                onClick={() => cancelSchedule(conflict.schedule.id)}
                              >
                                {cancelling && <span className="spinner-border spinner-border-sm me-1" />}
                                Cancel this assignment
                              </button> */}
                            </div>
                          )}

                          <div className="d-flex flex-wrap gap-1">
                            {group.slots.map((slot, i) => {
                              const full = slot.booked_count >= slot.capacity;
                              const isSelected = selection[group.weekday]?.start_time === slot.start_time;
                              return (
                                <button
                                  key={i}
                                  type="button"
                                  disabled={full}
                                  onClick={() => pickSlot(group.weekday, slot)}
                                  className={`schedule-btn ${isSelected ? "admin-theme-btn" : full ? "btn-light" : "available-schedule"}`}
                                  style={{ opacity: full ? 0.5 : 1 }}
                                >
                                  {fmt12(slot.start_time)} - {fmt12(slot.end_time)}
                                </button>
                              );
                            })}
                          </div>

                          {conflict && (
                            <p className="text-muted small mt-1 mb-0">
                              A new selection here will only apply to dates in your range not already covered by the assignment above.
                            </p>
                          )}
                        </div>
                      );
                    })}

                    {groups.length > 0 && (
                      <button className="admin-theme-btn" onClick={submitWeekdaySchedule} disabled={submitWeekdayLoading}>
                        {submitWeekdayLoading ? (
                          <><span className="spinner-border spinner-border-sm me-2" />Confirming...</>
                        ) : (
                          "Confirm schedule"
                        )}
                      </button>
                    )}
                  </>
                )}

                {mode === "date" && (
                  <>
                    <p className="fw-medium mb-2">
                      {dateRangeStart && dateRangeEnd && dateRangeEnd !== dateRangeStart
                        ? `${dateRangeStart} to ${dateRangeEnd}`
                        : dateRangeStart
                          ? dateRangeStart
                          : "Pick a date (or a range) on the calendar"}
                    </p>

                    {dateRangeStart && (
                      <button className="admin-theme-btn mb-3" onClick={loadDateSlots} disabled={loadDateSlotsLoading}>
                        {loadDateSlotsLoading ? (
                          <><span className="spinner-border spinner-border-sm me-2" />Loading...</>
                        ) : (
                          "Load slots"
                        )}
                      </button>
                    )}

                    {dateModeError && <p className="text-danger small mb-3">{dateModeError}</p>}

                    {dateSlotsLoaded &&
                      Object.keys(perDateSlots)
                        .sort()
                        .map((dateKey) => {
                          const existing = getExistingBookingForDate(dateKey);
                          const slotsForDate = perDateSlots[dateKey];
                          const cancelling = existing ? !!cancelLoading[`booking-${existing.booking.id}`] : false;
                          return (
                            <div key={dateKey} className="time-slot-bx">
                              <h4>{dateKey}</h4>

                              {existing ? (
                                <div className="already-assign d-flex align-items-center gap-3 flex-wrap mb-2">
                                  <span className="small">
                                    Already assigned: {fmt12(existing.booking.time_slots.start_time)} -{" "}
                                    {fmt12(existing.booking.time_slots.end_time)}
                                  </span>
                                  {/* <button
                                    className="btn btn-sm btn-outline-danger ms-auto"
                                    disabled={cancelling}
                                    onClick={() => cancelDateBooking(existing.booking.id)}
                                  >
                                    {cancelling && <span className="spinner-border spinner-border-sm me-1" />}
                                    Cancel this assignment
                                  </button> */}
                                </div>
                              ) : slotsForDate.length === 0 ? (
                                <p className="text-muted small mb-0">No slots exist for this date.</p>
                              ) : (
                                <div className="d-flex flex-wrap gap-2">
                                  {slotsForDate.map((slot) => {
                                    const full = slot.booked_count >= slot.capacity;
                                    const isSelected = perDateSelection[dateKey]?.id === slot.id;
                                    return (
                                      <button
                                        key={slot.id}
                                        type="button"
                                        disabled={full}
                                        onClick={() => pickDateSlot(dateKey, slot)}
                                        className={`schedule-btn ${isSelected ? "admin-theme-btn" : full ? "btn-light" : "available-schedule"}`}
                                        style={{ opacity: full ? 0.5 : 1 }}
                                      >
                                        {fmt12(slot.start_time)} - {fmt12(slot.end_time)}
                                      </button>
                                    );
                                  })}
                                </div>
                              )}
                            </div>
                          );
                        })}

                    {Object.keys(perDateSelection).length > 0 && (
                      <button className="admin-theme-btn" onClick={assignSpecificDates} disabled={assignDatesLoading}>
                        {assignDatesLoading ? (
                          <><span className="spinner-border spinner-border-sm me-2" />Assigning...</>
                        ) : (
                          `Assign selected date${Object.keys(perDateSelection).length > 1 ? "s" : ""}`
                        )}
                      </button>
                    )}
                  </>
                )}

                {statusMsg && <p className={`small mt-3 mb-0 ${statusIsError ? "text-danger" : "text-success"}`}>{statusMsg}</p>}
              </div>
            </div>
          </div>
        </div>
      </div>

      {/* Assigned slots calendar: shows every booked date at a glance and lets you swap
          the slot for one specific date without touching the rest of the schedule. */}
      {studentId && (
        <div className="card-theme p-4 mt-4">
          <h6 className="mb-3">Assigned Calendar</h6>
          <div className="row">
            <div className="col-lg-6">
              <div className="border rounded p-3">
                <div className="d-flex calendar-control justify-content-between align-items-center mb-2">
                  <button className="default-btn" onClick={goPrevAssignedMonth}>
                    <i className="bi bi-chevron-left"></i>
                  </button>
                  <span className="fw-semibold">{assignedMonthLabel}</span>
                  <button className="default-btn" onClick={goNextAssignedMonth}>
                    <i className="bi bi-chevron-right"></i>
                  </button>
                </div>
                <p className="text-muted small mb-2">Click a highlighted date to change or cancel its assigned slot.</p>

                <div className="d-grid schedule-slot" style={{ gridTemplateColumns: "repeat(7, 1fr)", gap: 4 }}>
                  {WEEKDAYS.map((wd) => (
                    <div key={wd} className="text-center small fw-semibold text-muted">
                      {wd.slice(0, 2)}
                    </div>
                  ))}

                  {assignedCells.map((cell, idx) => {
                    if (!cell.dateKey) return <div key={idx} />;
                    const entry = bookingsByDate[cell.dateKey];
                    const isSelected = changeDate === cell.dateKey;
                    const past = isPastDate(cell.dateKey);
                    const clickable = !!entry && !past;

                    return (
                      <button
                        key={idx}
                        onClick={() => (clickable ? openChangeSlot(cell.dateKey!) : undefined)}
                        disabled={!clickable}
                        title={entry && past ? "This class date has already passed" : undefined}
                        className={`schedule-btn d-flex flex-column align-items-center justify-content-center ${isSelected ? "schedule-selected" : entry ? "available-schedule" : "not-available"
                          }`}
                        style={{ opacity: entry ? (past ? 0.4 : 1) : 0.80, lineHeight: 1.1 }}
                      >
                        <span>{cell.dayNumber}</span>
                        {entry && <span style={{ fontSize: 11 }}>{fmt12(entry.booking.time_slots.start_time)}- {fmt12(entry.booking.time_slots.end_time)}</span>}
                      </button>
                    );
                  })}
                </div>
              </div>
            </div>

            <div className="col-lg-6 mt-4 mt-lg-0">
              <div className="border rounded p-3 h-100">
                {!changeDate && <p className="text-muted small mb-0">Select a booked date on the calendar to change or cancel its slot.</p>}

                {changeDate && bookingsByDate[changeDate] && (
                  <>
                    <p className="fw-medium mb-2">{changeDate}</p>
                    <p className="small text-muted mb-2">
                      Currently: {fmt12(bookingsByDate[changeDate].booking.time_slots.start_time)} -{" "}
                      {fmt12(bookingsByDate[changeDate].booking.time_slots.end_time)}
                    </p>

                    <div className="d-flex flex-wrap gap-2 mb-3">
                      {(slotsByDate[changeDate] ?? []).map((slot) => {
                        const isCurrent = slot.id === bookingsByDate[changeDate].booking.time_slot_id;
                        const full = slot.booked_count >= slot.capacity && !isCurrent;
                        const isSelected = changeDateSlot?.id === slot.id;
                        return (
                          <button
                            key={slot.id}
                            type="button"
                            disabled={isCurrent || full}
                            onClick={() => setChangeDateSlot(slot)}
                            className={`btn btn-sm ${isSelected ? "admin-theme-btn" : "btn-outline-secondary"}`}
                            style={{ opacity: isCurrent || full ? 0.5 : 1 }}
                          >
                            {fmt12(slot.start_time)} - {fmt12(slot.end_time)}
                            {isCurrent ? " (current)" : ""}
                          </button>
                        );
                      })}
                    </div>

                    <div className="d-flex gap-2">
                      <button className="admin-theme-btn" onClick={submitChangeSlot} disabled={!changeDateSlot || changeSlotLoading}>
                        {changeSlotLoading ? (
                          <><span className="spinner-border spinner-border-sm me-2" />Changing...</>
                        ) : (
                          "Change slot"
                        )}
                      </button>
                      <button
                        className="btn btn-sm btn-outline-danger"
                        disabled={!!cancelLoading[`booking-${bookingsByDate[changeDate].booking.id}`]}
                        onClick={async () => {
                          const bookingId = bookingsByDate[changeDate].booking.id;
                          await cancelDateBooking(bookingId);
                          setChangeDate(null);
                          setChangeDateSlot(null);
                        }}
                      >
                        {cancelLoading[`booking-${bookingsByDate[changeDate].booking.id}`] && (
                          <span className="spinner-border spinner-border-sm me-1" />
                        )}
                        Cancel this slot
                      </button>
                      <button
                        className="btn btn-sm btn-outline-secondary"
                        onClick={() => {
                          setChangeDate(null);
                          setChangeDateSlot(null);
                        }}
                      >
                        Close
                      </button>
                    </div>
                  </>
                )}
              </div>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}