// 3-month calendar component for blocking dates and viewing bookings.
// Supports click-individual-day toggling and click-and-drag range selection.

const { useState, useMemo, useRef, useEffect } = React;

const MONTH_NAMES = [
  "January", "February", "March", "April", "May", "June",
  "July", "August", "September", "October", "November", "December",
];
const DAY_LABELS = ["S", "M", "T", "W", "T", "F", "S"];

function parseKey(k) {
  const [y, m, d] = k.split("-").map(Number);
  return new Date(y, m - 1, d);
}

function isBetween(dateStr, startStr, endStr) {
  return dateStr >= startStr && dateStr <= endStr;
}

function MonthGrid({
  year,
  month, // 0-indexed
  bookings,
  blocks,
  selection,
  onDayMouseDown,
  onDayMouseEnter,
  onDayMouseUp,
  todayKey,
  hoveredBookingId,
  setHoveredBookingId,
}) {
  const firstDay = new Date(year, month, 1);
  const startWeekday = firstDay.getDay();
  const daysInMonth = new Date(year, month + 1, 0).getDate();

  const cells = [];
  for (let i = 0; i < startWeekday; i++) cells.push(null);
  for (let d = 1; d <= daysInMonth; d++) cells.push(d);
  while (cells.length % 7 !== 0) cells.push(null);

  return (
    <div className="month-grid">
      <div className="month-header">
        {MONTH_NAMES[month]} {year}
      </div>
      <div className="dow-row">
        {DAY_LABELS.map((l, i) => (
          <div key={i} className="dow">{l}</div>
        ))}
      </div>
      <div className="day-grid">
        {cells.map((d, i) => {
          if (d === null) return <div key={i} className="day-cell empty" />;

          const k = `${year}-${String(month + 1).padStart(2, "0")}-${String(d).padStart(2, "0")}`;
          const isToday = k === todayKey;
          const isPast = k < todayKey;

          // Find booking covering this day
          const booking = bookings.find((b) => isBetween(k, b.start, b.end));
          // Find block covering this day
          const block = blocks.find((b) => isBetween(k, b.start, b.end));

          // Check selection (in-progress range)
          let inSelection = false;
          if (selection) {
            const [a, b] = selection.start <= selection.end
              ? [selection.start, selection.end]
              : [selection.end, selection.start];
            inSelection = k >= a && k <= b;
          }

          const classes = ["day-cell"];
          if (isToday) classes.push("today");
          if (isPast) classes.push("past");
          if (booking) classes.push("booked");
          if (block) classes.push("blocked");
          if (inSelection) classes.push("selecting");
          if (booking && hoveredBookingId === booking.id) classes.push("highlight-booking");

          // Range edges for booking
          if (booking) {
            if (booking.start === k) classes.push("range-start");
            if (booking.end === k) classes.push("range-end");
          }
          if (block) {
            if (block.start === k) classes.push("range-start");
            if (block.end === k) classes.push("range-end");
          }

          return (
            <div
              key={i}
              className={classes.join(" ")}
              onMouseDown={(e) => onDayMouseDown(k, e)}
              onMouseEnter={() => {
                onDayMouseEnter(k);
                if (booking) setHoveredBookingId(booking.id);
              }}
              onMouseLeave={() => {
                if (booking) setHoveredBookingId(null);
              }}
              onMouseUp={() => onDayMouseUp(k)}
              title={
                booking
                  ? `${booking.ref} · ${booking.customer}`
                  : block
                  ? `Blocked: ${block.reason || ""}`
                  : ""
              }
            >
              <span className="day-num">{d}</span>
            </div>
          );
        })}
      </div>
    </div>
  );
}

function BookingCalendar({ vehicle, bookings, blocks, onAddBlock, onRemoveBlock }) {
  const { dateKey, addDays } = window.RENTAL_DATA;
  const todayKey = dateKey(new Date());

  // Anchor month state — first of three visible months
  const [anchor, setAnchor] = useState(() => {
    const t = new Date();
    return { year: t.getFullYear(), month: t.getMonth() };
  });

  const [selection, setSelection] = useState(null); // {start, end, mode: 'drag' | 'click'}
  const [pendingReason, setPendingReason] = useState("");
  const [pendingRange, setPendingRange] = useState(null); // confirmed range awaiting reason
  const dragStartedRef = useRef(false);
  const [hoveredBookingId, setHoveredBookingId] = useState(null);

  // Resolve three months
  const months = useMemo(() => {
    const arr = [];
    for (let i = 0; i < 3; i++) {
      const m = anchor.month + i;
      const yr = anchor.year + Math.floor(m / 12);
      const mo = ((m % 12) + 12) % 12;
      arr.push({ year: yr, month: mo });
    }
    return arr;
  }, [anchor]);

  const shiftMonths = (delta) => {
    const m = anchor.month + delta;
    const yr = anchor.year + Math.floor(m / 12);
    const mo = ((m % 12) + 12) % 12;
    setAnchor({ year: yr, month: mo });
  };

  const goToToday = () => {
    const t = new Date();
    setAnchor({ year: t.getFullYear(), month: t.getMonth() });
  };

  const handleMouseDown = (k, e) => {
    if (k < todayKey) return;
    // Don't start a block on a booked day (those are customer reservations)
    const onBooking = bookings.some((b) => isBetween(k, b.start, b.end));
    if (onBooking) return;

    // Check if clicking an existing block — offer to remove
    const existingBlock = blocks.find((b) => isBetween(k, b.start, b.end));
    if (existingBlock && !e.shiftKey) {
      if (confirm(`Remove block "${existingBlock.reason || "Blocked"}"?`)) {
        onRemoveBlock(existingBlock);
      }
      return;
    }

    dragStartedRef.current = true;
    setSelection({ start: k, end: k });
  };

  const handleMouseEnter = (k) => {
    if (dragStartedRef.current && selection) {
      setSelection({ ...selection, end: k });
    }
  };

  const handleMouseUp = (k) => {
    if (!dragStartedRef.current || !selection) {
      dragStartedRef.current = false;
      return;
    }
    dragStartedRef.current = false;

    const start = selection.start <= selection.end ? selection.start : selection.end;
    const end = selection.start <= selection.end ? selection.end : selection.start;

    // If range overlaps a booking, abort
    const overlapsBooking = bookings.some(
      (b) => !(end < b.start || start > b.end)
    );
    if (overlapsBooking) {
      alert("Selection overlaps a customer booking. Cannot block these dates.");
      setSelection(null);
      return;
    }

    setPendingRange({ start, end });
    setSelection(null);
  };

  // Listen for global mouseup so dragging out of grid still ends
  useEffect(() => {
    const onUp = () => {
      if (dragStartedRef.current && selection) {
        handleMouseUp(selection.end);
      }
    };
    window.addEventListener("mouseup", onUp);
    return () => window.removeEventListener("mouseup", onUp);
    // eslint-disable-next-line
  }, [selection]);

  const confirmBlock = () => {
    if (!pendingRange) return;
    onAddBlock({
      start: pendingRange.start,
      end: pendingRange.end,
      reason: pendingReason || "Blocked",
    });
    setPendingRange(null);
    setPendingReason("");
  };

  const cancelBlock = () => {
    setPendingRange(null);
    setPendingReason("");
  };

  // Sorted booking list for sidebar
  const sortedBookings = [...bookings].sort((a, b) => a.start.localeCompare(b.start));
  const upcomingBookings = sortedBookings.filter((b) => b.end >= todayKey);

  return (
    <div className="calendar-wrap">
      <div className="calendar-toolbar">
        <div className="cal-nav">
          <button className="btn-icon" onClick={() => shiftMonths(-1)}>‹</button>
          <button className="btn-ghost" onClick={goToToday}>Today</button>
          <button className="btn-icon" onClick={() => shiftMonths(1)}>›</button>
          <span className="cal-range-label">
            {MONTH_NAMES[months[0].month]} {months[0].year} — {MONTH_NAMES[months[2].month]} {months[2].year}
          </span>
        </div>
        <div className="cal-legend">
          <span className="legend-item"><span className="legend-swatch swatch-booked"></span>Booked</span>
          <span className="legend-item"><span className="legend-swatch swatch-blocked"></span>Blocked</span>
          <span className="legend-item"><span className="legend-swatch swatch-today"></span>Today</span>
        </div>
      </div>

      <div className="calendar-body">
        <div className="months-row" onMouseLeave={() => setHoveredBookingId(null)}>
          {months.map((m, i) => (
            <MonthGrid
              key={`${m.year}-${m.month}-${i}`}
              year={m.year}
              month={m.month}
              bookings={bookings}
              blocks={blocks}
              selection={selection}
              onDayMouseDown={handleMouseDown}
              onDayMouseEnter={handleMouseEnter}
              onDayMouseUp={handleMouseUp}
              todayKey={todayKey}
              hoveredBookingId={hoveredBookingId}
              setHoveredBookingId={setHoveredBookingId}
            />
          ))}
        </div>

        <aside className="cal-sidebar">
          <div className="sidebar-section">
            <h4>Upcoming bookings</h4>
            {upcomingBookings.length === 0 && (
              <p className="muted">No upcoming bookings.</p>
            )}
            <ul className="booking-list">
              {upcomingBookings.map((b) => {
                const start = parseKey(b.start);
                const end = parseKey(b.end);
                const days = Math.round((end - start) / 86400000) + 1;
                return (
                  <li
                    key={b.id}
                    className={`booking-item ${hoveredBookingId === b.id ? "hover" : ""}`}
                    onMouseEnter={() => setHoveredBookingId(b.id)}
                    onMouseLeave={() => setHoveredBookingId(null)}
                  >
                    <div className="booking-ref">{b.ref}</div>
                    <div className="booking-customer">{b.customer}</div>
                    <div className="booking-dates">
                      {start.toLocaleDateString(undefined, { month: "short", day: "numeric" })}
                      {" → "}
                      {end.toLocaleDateString(undefined, { month: "short", day: "numeric" })}
                      <span className="booking-days"> · {days} {days === 1 ? "day" : "days"}</span>
                    </div>
                  </li>
                );
              })}
            </ul>
          </div>

          <div className="sidebar-section">
            <h4>Blocked dates</h4>
            {blocks.length === 0 && (
              <p className="muted">None. Drag to select dates, or click a single day.</p>
            )}
            <ul className="block-list">
              {blocks.map((b, i) => (
                <li key={i} className="block-item">
                  <div>
                    <div className="block-reason">{b.reason || "Blocked"}</div>
                    <div className="block-dates">
                      {parseKey(b.start).toLocaleDateString(undefined, { month: "short", day: "numeric" })}
                      {b.start !== b.end && ` → ${parseKey(b.end).toLocaleDateString(undefined, { month: "short", day: "numeric" })}`}
                    </div>
                  </div>
                  <button className="btn-link-danger" onClick={() => onRemoveBlock(b)}>Remove</button>
                </li>
              ))}
            </ul>
          </div>

          <div className="sidebar-help">
            <strong>How to block:</strong> Click a single day, or click + drag across a range. Click an existing block to remove it.
          </div>
        </aside>
      </div>

      {pendingRange && (
        <div className="modal-backdrop" onClick={cancelBlock}>
          <div className="modal" onClick={(e) => e.stopPropagation()}>
            <h3>Block dates</h3>
            <p className="modal-sub">
              {parseKey(pendingRange.start).toLocaleDateString(undefined, {
                weekday: "short", month: "short", day: "numeric", year: "numeric",
              })}
              {pendingRange.start !== pendingRange.end && (
                <> → {parseKey(pendingRange.end).toLocaleDateString(undefined, {
                  weekday: "short", month: "short", day: "numeric", year: "numeric",
                })}</>
              )}
            </p>
            <label className="form-label">Reason (optional)</label>
            <input
              type="text"
              className="form-input"
              autoFocus
              placeholder="e.g. Maintenance, Owner use, Cleaning"
              value={pendingReason}
              onChange={(e) => setPendingReason(e.target.value)}
              onKeyDown={(e) => {
                if (e.key === "Enter") confirmBlock();
                if (e.key === "Escape") cancelBlock();
              }}
            />
            <div className="modal-actions">
              <button className="btn-ghost" onClick={cancelBlock}>Cancel</button>
              <button className="btn-primary" onClick={confirmBlock}>Block dates</button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

window.BookingCalendar = BookingCalendar;
