"use client";
import { useEffect, useMemo, useState } from "react";
import axiosInstance from "@/lib/axiosInstance";
import { WEEKDAYS, fmt12 } from "@/lib/timeslot-utils";
import { ColumnDef } from "@tanstack/react-table";
import DataTable from "@/components/common/DataTable";

interface BookingWithTime {
  id: number;
  time_slot_id: number;
  booking_date: string;
  time_slots: { start_time: string; end_time: string };
}
interface ScheduleWithBookings {
  id: number;
  start_date: string;
  end_date: string;
  status: string;
  schedule_bookings: BookingWithTime[];
}
interface SlotOption {
  id: number;
  start_time: string;
  end_time: string;
  capacity: number;
  booked_count: number;
}
interface ChangeRequest {
  id: number;
  booking_id: number | null;
  current_booking_date: string | null;
  current_start_time: string | null;
  current_end_time: string | null;
  requested_date: string;
  requested_start_time: string;
  requested_end_time: string;
  reason: string | null;
  status: string;
  admin_note: string | null;
  created_at: string;
}

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;
}

// 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}`;
}

const statusBadgeClass = (status: string) => {
  switch (status) {
    case "approved": return "bg-success";
    case "rejected": return "bg-danger";
    case "cancelled": return "bg-secondary";
    default: return "bg-warning text-dark";
  }
};

export default function StudentSchedulePage() {
  const [schedules, setSchedules] = useState<ScheduleWithBookings[]>([]);
  const [requests, setRequests] = useState<ChangeRequest[]>([]);
  const [loading, setLoading] = useState(true);

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

  const [visibleMonth, setVisibleMonth] = useState(() => {
    const now = new Date();
    return new Date(now.getFullYear(), now.getMonth(), 1);
  });

  const [selectedDate, setSelectedDate] = useState<string | null>(null);

  // --- change request form state ---
  const [showForm, setShowForm] = useState(false);
  const [targetDate, setTargetDate] = useState("");
  const [slotOptions, setSlotOptions] = useState<SlotOption[]>([]);
  const [slotsLoading, setSlotsLoading] = useState(false);
  const [chosenSlot, setChosenSlot] = useState<SlotOption | null>(null);
  const [reason, setReason] = useState("");
  const [submitting, setSubmitting] = useState(false);

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

  useEffect(() => {
    loadAll();
  }, []);

  const loadAll = async () => {
    setLoading(true);
    try {
      const [scheduleRes, requestsRes] = await Promise.all([
        axiosInstance.get("/student/schedule"),
        axiosInstance.get("/student/schedule-requests"),
      ]);
      setSchedules(scheduleRes.data.data);
      setRequests(requestsRes.data.data);
    } finally {
      setLoading(false);
    }
  };

  const bookingsByDate = useMemo(() => {
    const map: Record<string, { schedule: ScheduleWithBookings; booking: BookingWithTime }> = {};
    for (const sched of schedules) {
      for (const b of sched.schedule_bookings) {
        map[b.booking_date.slice(0, 10)] = { schedule: sched, booking: b };
      }
    }
    return map;
  }, [schedules]);

  // Lookup by booking id (not just date) — used so the requests table can show
  // the correct "From" time even if that booking has since moved to a
  // different date/slot (e.g. after an earlier approved request).
  const bookingById = useMemo(() => {
    const map: Record<number, BookingWithTime> = {};
    for (const sched of schedules) {
      for (const b of sched.schedule_bookings) {
        map[b.id] = b;
      }
    }
    return map;
  }, [schedules]);

  const pendingRequestDates = useMemo(() => {
    const set = new Set<string>();
    for (const r of requests) {
      if (r.status === "pending" && r.current_booking_date) set.add(r.current_booking_date.slice(0, 10));
    }
    return set;
  }, [requests]);

  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 openDate = (dateKey: string) => {
    if (!bookingsByDate[dateKey]) return;
    setSelectedDate(dateKey);
    setShowForm(false);
  };

  const openChangeForm = () => {
    if (!selectedDate || isPastDate(selectedDate)) return; // guard: never open the form for a past class date
    setShowForm(true);
    setTargetDate("");
    setSlotOptions([]);
    setChosenSlot(null);
    setReason("");
  };

  const loadSlotsForTargetDate = async (dateKey: string) => {
    if (dateKey && isPastDate(dateKey)) {
      setStatusIsError(true);
      setStatusMsg("You can't request a past date.");
      return;
    }
    setTargetDate(dateKey);
    setChosenSlot(null);
    setSlotOptions([]);
    if (!dateKey) return;
    setSlotsLoading(true);
    try {
      const { data } = await axiosInstance.get(`/student/schedule/slots?start_date=${dateKey}&end_date=${dateKey}`);
      setSlotOptions(data.data[dateKey] ?? []);
    } finally {
      setSlotsLoading(false);
    }
  };

  const submitChangeRequest = async () => {
    if (!selectedDate) return;
    if (isPastDate(selectedDate)) {
      setStatusIsError(true);
      setStatusMsg("This class date has already passed and can no longer be changed.");
      return;
    }
    const current = bookingsByDate[selectedDate];
    if (!current) return;
    if (!targetDate || !chosenSlot) {
      setStatusIsError(true);
      setStatusMsg("Pick a new date and time slot first.");
      return;
    }
    if (isPastDate(targetDate)) {
      setStatusIsError(true);
      setStatusMsg("You can't request a past date.");
      return;
    }

    setSubmitting(true);
    try {
      await axiosInstance.post("/student/schedule-requests", {
        booking_id: current.booking.id,
        requested_date: targetDate,
        requested_start_time: chosenSlot.start_time,
        requested_end_time: chosenSlot.end_time,
        reason: reason.trim() || undefined,
      });
      setStatusIsError(false);
      setStatusMsg("Your change request has been submitted for review.");
      setShowForm(false);
      setSelectedDate(null);
      await loadAll();
    } catch (err: any) {
      setStatusIsError(true);
      setStatusMsg(err?.response?.data?.error ?? "Failed to submit request.");
    } finally {
      setSubmitting(false);
    }
  };

  const cancelRequest = async (id: number) => {
    try {
      await axiosInstance.delete(`/student/schedule-requests/${id}`);
      await loadAll();
    } catch (err: any) {
      setStatusIsError(true);
      setStatusMsg(err?.response?.data?.error ?? "Failed to cancel request.");
    }
  };

  const requestColumns = useMemo<ColumnDef<ChangeRequest>[]>(
    () => [
      {
        header: "From",
        cell: ({ row }) => {
          const r = row.original;
          const dateLabel = r.current_booking_date ? r.current_booking_date.slice(0, 10) : "—";

          if (!r.current_start_time || !r.current_end_time) {
            return <span className="small text-muted">{dateLabel}</span>;
          }

          return (
            <span className="small">
              {dateLabel}
              <br />
              {fmt12(r.current_start_time)} - {fmt12(r.current_end_time)}
            </span>
          );
        },
      },
      {
        header: "Requested",
        cell: ({ row }) => {
          const r = row.original;
          return (
            <span className="small">
              {r.requested_date.slice(0, 10)}
              <br />
              {fmt12(r.requested_start_time)} - {fmt12(r.requested_end_time)}
            </span>
          );
        },
      },
      {
        header: "Reason",
        accessorFn: (r) => r.reason || "—",
        id: "reason",
      },
      {
        header: "Status",
        cell: ({ row }) => (
          <span className={`badge ${statusBadgeClass(row.original.status)}`}>{row.original.status}</span>
        ),
      },
      {
        header: "Admin note",
        accessorFn: (r) => r.admin_note || "—",
        id: "admin_note",
      },
      {
        header: "Actions",
        cell: ({ row }) => {
          const r = row.original;
          if (r.status !== "pending") return null;
          return (
            <button className="btn btn-sm btn-outline-danger" onClick={() => cancelRequest(r.id)}>
              Cancel
            </button>
          );
        },
      },
    ],
    [requests]
  );

  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">My Schedule</h2>
            <p className="admin-page-subtitle">View your assigned classes and request changes</p>
          </div>
        </div>
      </div>

      {statusMsg && (
        <div className={`alert ${statusIsError ? "alert-danger" : "alert-success"} py-2`}>{statusMsg}</div>
      )}

      <div className="card-theme p-4">
        <div className="row">
          {/* LEFT: calendar of assigned classes */}
          <div className="col-lg-6">
            <div className="border rounded p-2">
              <div className="d-flex justify-content-between align-items-center my-2">
                <button className="btn btn-sm btn-outline-secondary" onClick={goPrevMonth}>
                  <i className="bi bi-chevron-left" />
                </button>
                <span className="fw-semibold">{monthLabel}</span>
                <button className="btn btn-sm btn-outline-secondary" onClick={goNextMonth}>
                  <i className="bi bi-chevron-right" />
                </button>
              </div>
              <p className="text-muted small mb-2">Click a highlighted date to view or request a change.</p>

              <div className="d-grid" 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 entry = bookingsByDate[cell.dateKey];
                  const isSelected = selectedDate === cell.dateKey;
                  const hasPendingReq = pendingRequestDates.has(cell.dateKey);
                  const past = isPastDate(cell.dateKey);

                  return (
                    <button
                      key={idx}
                      onClick={() => openDate(cell.dateKey!)}
                      disabled={!entry}
                      className={`btn btn-sm p-1 d-flex flex-column align-items-center justify-content-center ${isSelected ? "admin-theme-btn" : entry ? "btn-outline-primary" : "btn-light"
                        }`}
                      style={{
                        height: 44,
                        fontSize: 11,
                        opacity: entry ? (past ? 0.55 : 1) : 0.35,
                        lineHeight: 1.1,
                        position: "relative",
                      }}
                    >
                      <span style={{ fontSize: 12 }}>{cell.dayNumber}</span>
                      {entry && (
                        <span style={{ fontSize: 11 }}>
                          {fmt12(entry.booking.time_slots.start_time)}-{fmt12(entry.booking.time_slots.end_time)}
                        </span>
                      )}
                      {hasPendingReq && (
                        <span
                          className="badge bg-warning"
                          style={{ position: "absolute", top: 2, right: 2, width: 6, height: 6, padding: 0, borderRadius: "50%" }}
                        />
                      )}
                    </button>
                  );
                })}
              </div>

              {loading && <p className="text-muted small mt-2 mb-0">Loading...</p>}
              {!loading && Object.keys(bookingsByDate).length === 0 && (
                <p className="text-muted small mt-3 mb-0">No upcoming classes scheduled.</p>
              )}
            </div>
          </div>

          {/* RIGHT: selected date details / change request form */}
          <div className="col-lg-6 mt-4 mt-lg-0">
            <div className="border rounded p-3 h-100">
              {!selectedDate && <p className="text-muted small mb-0">Select a scheduled date on the calendar.</p>}

              {selectedDate && bookingsByDate[selectedDate] && !showForm && (
                <>
                  <p className="fw-medium mb-2">{selectedDate}</p>
                  <p className="small text-muted mb-3">
                    Class time: {fmt12(bookingsByDate[selectedDate].booking.time_slots.start_time)} -{" "}
                    {fmt12(bookingsByDate[selectedDate].booking.time_slots.end_time)}
                  </p>

                  {isPastDate(selectedDate) ? (
                    <p className="small text-muted mb-0">
                      <i className="bi bi-clock-history me-1" />
                      This class date has already passed and can no longer be changed.
                    </p>
                  ) : pendingRequestDates.has(selectedDate) ? (
                    <p className="small text-warning-emphasis mb-0">
                      <i className="bi bi-hourglass-split me-1" />
                      A change request for this date is already pending review.
                    </p>
                  ) : (
                    <button className="admin-theme-btn" onClick={openChangeForm}>
                      Request a Schedule Change
                    </button>
                  )}
                </>
              )}

              {selectedDate && showForm && !isPastDate(selectedDate) && (
                <>
                  <p className="fw-medium mb-3">Request change for {selectedDate}</p>

                  <div className="mb-3">
                    <label className="form-label small">New date</label>
                    <input
                      type="date"
                      className="form-control form-control-sm"
                      value={targetDate}
                      min={todayKey}
                      onChange={(e) => loadSlotsForTargetDate(e.target.value)}
                    />
                  </div>

                  {slotsLoading && <p className="text-muted small">Loading available slots...</p>}

                  {!slotsLoading && targetDate && slotOptions.length === 0 && (
                    <p className="text-muted small">No slots exist for that date.</p>
                  )}

                  {!slotsLoading && slotOptions.length > 0 && (
                    <div className="mb-3">
                      <label className="form-label small d-block">New time slot</label>
                      <div className="d-flex flex-wrap gap-2">
                        {slotOptions.map((slot) => {
                          const current = selectedDate ? bookingsByDate[selectedDate] : null;
                          const isCurrent =
                            !!current &&
                            targetDate === selectedDate &&
                            slot.start_time === current.booking.time_slots.start_time &&
                            slot.end_time === current.booking.time_slots.end_time;

                          const full = slot.booked_count >= slot.capacity && !isCurrent;
                          const isSelected = chosenSlot?.id === slot.id;

                          return (
                            <button
                              key={slot.id}
                              type="button"
                              disabled={isCurrent || full}
                              onClick={() => setChosenSlot(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>
                  )}

                  <div className="mb-3">
                    <label className="form-label small">Reason (optional)</label>
                    <textarea
                      className="form-control form-control-sm"
                      rows={3}
                      value={reason}
                      onChange={(e) => setReason(e.target.value)}
                      placeholder="Let us know why you need to move this class"
                    />
                  </div>

                  <div className="d-flex gap-2">
                    <button className="admin-theme-btn" onClick={submitChangeRequest} disabled={submitting}>
                      {submitting ? (
                        <span className="spinner-border spinner-border-sm me-2" />
                      ) : null}
                      Submit Request
                    </button>
                    <button className="btn btn-sm btn-outline-secondary" onClick={() => setShowForm(false)}>
                      Cancel
                    </button>
                  </div>
                </>
              )}
            </div>
          </div>
        </div>
      </div>

      <div className="admin-page-header">
        <div className="d-flex justify-content-between align-items-center">
          <div>
            <h2 className="admin-page-title mt-4">
              My Schedule Change Requests
            </h2>
            <p className="admin-page-subtitle">
              Submit new schedule change requests and monitor the status of your existing requests.
            </p>
          </div>
        </div>
      </div>
      <div className="admin-table-section">
        {requests.length === 0 ? (
          <p className="text-muted small mb-0">You haven't submitted any change requests.</p>
        ) : (
          <DataTable columns={requestColumns} data={requests} />
        )}
      </div>
    </div>
  );
}