// Desktop calendar — two-month spreadsheet view
// Layout: left rail (mini nav + categories) | main grid (two months) | right drawer (selected day)

const { useState, useMemo, useEffect, useRef } = React;
const {
  MONTH_NAMES, MONTH_SHORT, DOW_NARROW, DOW_SHORT, DOW_LONG,
  keyOf, parseKey, addDays, addMonths, dowMon,
  monthGrid, eventsOnDate, sortEvents, clipTitle, fmtLong, fmtMonthYear,
} = window.CAL_UTILS;

// ─────────────────────────────────────────────────────────────────────
// Mini month — used in left rail and as picker
function MiniMonth({ year, month0, selectedKey, viewStartKey, onPick, dim = false }) {
  const cells = monthGrid(year, month0);
  const events = window.CALENDAR_DATA.EVENTS;

  return (
    <div className="mini-month">
      <div className="mini-month-title">{MONTH_NAMES[month0]} {year}</div>
      <div className="mini-month-dows">
        {DOW_NARROW.map((d, i) => <div key={i} className="mini-dow">{d}</div>)}
      </div>
      <div className="mini-month-grid">
        {cells.map((date) => {
          const k = keyOf(date);
          const inMonth = date.getMonth() === month0;
          const isToday = k === keyOf(new Date());
          const isSelected = k === selectedKey;
          const has = eventsOnDate(events, k).length > 0;
          return (
            <button
              key={k}
              onClick={() => onPick(k)}
              className={`mini-cell ${inMonth ? "" : "out"} ${isToday ? "today" : ""} ${isSelected ? "sel" : ""}`}
            >
              <span>{date.getDate()}</span>
              {has && inMonth && <span className="mini-dot" />}
            </button>
          );
        })}
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────
// Lane assignment for a single week. Returns { placed, hiddenByDay } where
// placed is [{event, lane, startCol, endCol, continuesLeft, continuesRight}]
// and hiddenByDay is a map of col → count of events forced past MAX_LANES.
const MAX_LANES = 3;

function buildWeekLanes(weekStart, events) {
  const weekEnd = addDays(weekStart, 6);
  const weekStartKey = keyOf(weekStart);
  const weekEndKey = keyOf(weekEnd);

  const touching = [];
  for (const e of events) {
    const sKey = e.date;
    const eKey = e.endDate || e.date;
    if (eKey < weekStartKey || sKey > weekEndKey) continue;
    const startCol = sKey < weekStartKey ? 0 : dowMon(parseKey(sKey));
    const endCol   = eKey > weekEndKey   ? 6 : dowMon(parseKey(eKey));
    const isMulti = (e.endDate && e.endDate !== e.date) || e.allDay;
    touching.push({
      event: e,
      startCol,
      endCol,
      continuesLeft: sKey < weekStartKey,
      continuesRight: eKey > weekEndKey,
      isMulti,
    });
  }

  // Sort: multi-day/all-day first, then earlier start, then longer span, then start time.
  touching.sort((a, b) => {
    if (a.isMulti !== b.isMulti) return a.isMulti ? -1 : 1;
    if (a.startCol !== b.startCol) return a.startCol - b.startCol;
    const lenDiff = (b.endCol - b.startCol) - (a.endCol - a.startCol);
    if (lenDiff !== 0) return lenDiff;
    return ((a.event.start || "") || "").localeCompare(b.event.start || "");
  });

  // Greedy lane packing.
  const lanes = []; // lane index → array of {startCol, endCol}
  const placed = [];
  for (const t of touching) {
    let lane = 0;
    while (lanes[lane] && lanes[lane].some(x => !(x.endCol < t.startCol || t.endCol < x.startCol))) {
      lane++;
    }
    if (!lanes[lane]) lanes[lane] = [];
    lanes[lane].push({ startCol: t.startCol, endCol: t.endCol });
    placed.push({ ...t, lane });
  }

  // For each day, count events whose lane >= MAX_LANES.
  const hiddenByDay = [0, 0, 0, 0, 0, 0, 0];
  for (const p of placed) {
    if (p.lane < MAX_LANES) continue;
    for (let c = p.startCol; c <= p.endCol; c++) hiddenByDay[c]++;
  }

  return { placed: placed.filter(p => p.lane < MAX_LANES), hiddenByDay };
}

// ─────────────────────────────────────────────────────────────────────
function WeekRow({ weekStart, month0, selectedKey, onSelect, todayKey }) {
  const cats = window.CALENDAR_DATA.CATEGORIES;
  const events = window.CALENDAR_DATA.EVENTS;
  const { placed, hiddenByDay } = buildWeekLanes(weekStart, events);

  const days = Array.from({ length: 7 }, (_, i) => addDays(weekStart, i));

  return (
    <div className="week-row">
      {days.map((date) => {
        const k = keyOf(date);
        const inMonth = date.getMonth() === month0;
        const isToday = k === todayKey;
        const isSel = k === selectedKey;
        return (
          <button
            key={k}
            className={`day-cell ${inMonth ? "" : "out"} ${isToday ? "today" : ""} ${isSel ? "sel" : ""}`}
            onClick={() => onSelect(k)}
            type="button"
          >
            <div className="day-num-row">
              <span className="day-num">{date.getDate()}</span>
              {isToday && <span className="today-pip">today</span>}
            </div>
          </button>
        );
      })}

      <div className="week-overlay">
        {placed.map((p) => {
          const c = cats[p.event.cat] || cats.personal;
          const cls = [
            "banner",
            p.event.allDay || p.isMulti ? "banner-band" : "banner-chip",
            p.continuesLeft ? "continues-left" : "",
            p.continuesRight ? "continues-right" : "",
          ].join(" ");
          return (
            <button
              key={p.event.id + "@" + keyOf(weekStart)}
              type="button"
              className={cls}
              style={{
                gridColumn: `${p.startCol + 1} / ${p.endCol + 2}`,
                gridRow: p.lane + 1,
                background: p.isMulti || p.event.allDay ? c.soft : "transparent",
                color: p.isMulti || p.event.allDay ? c.ink : "var(--ink)",
                borderLeftColor: c.dot,
              }}
              title={`${p.event.title}${p.event.start ? " · " + p.event.start : ""}`}
              onClick={(ev) => { ev.stopPropagation(); window.openEventEditor({ initial: p.event }); }}
            >
              {!p.isMulti && !p.event.allDay && (
                <span className="banner-dot" style={{ background: c.dot }} />
              )}
              {!p.isMulti && !p.event.allDay && p.event.start && (
                <span className="banner-time">{p.event.start}</span>
              )}
              <span className="banner-title">{p.event.title}</span>
            </button>
          );
        })}
        {hiddenByDay.map((n, col) => n > 0 && (
          <button
            key={`more-${col}`}
            type="button"
            className="banner-more"
            style={{ gridColumn: `${col + 1} / ${col + 2}`, gridRow: MAX_LANES + 1 }}
            onClick={(ev) => { ev.stopPropagation(); onSelect(keyOf(addDays(weekStart, col))); }}
          >+{n} more</button>
        ))}
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────
function MonthBlock({ year, month0, selectedKey, onSelect }) {
  const cells = monthGrid(year, month0);
  const todayKey = keyOf(new Date());
  // Split into 6 weeks (rows of 7).
  const weeks = [];
  for (let i = 0; i < 6; i++) weeks.push(cells[i * 7]);

  return (
    <div className="month-block">
      <header className="month-header">
        <h2 className="month-title">
          <span className="month-name">{MONTH_NAMES[month0]}</span>
          <span className="month-year">{year}</span>
        </h2>
      </header>
      <div className="dow-row">
        {DOW_SHORT.map((d) => <div key={d} className="dow-cell">{d}</div>)}
      </div>
      <div className="month-grid">
        {weeks.map((weekStart) => (
          <WeekRow
            key={keyOf(weekStart)}
            weekStart={weekStart}
            month0={month0}
            selectedKey={selectedKey}
            onSelect={onSelect}
            todayKey={todayKey}
          />
        ))}
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────
function DayDrawer({ dateKey, onClose, onJump }) {
  const habitState = window.useHabits();
  if (!dateKey) return null;
  const date = parseKey(dateKey);
  const evts = sortEvents(eventsOnDate(window.CALENDAR_DATA.EVENTS, dateKey));
  const cats = window.CALENDAR_DATA.CATEGORIES;
  const habits = window.CALENDAR_DATA.HABITS;

  const allDay = evts.filter(e => e.allDay);
  const timed = evts.filter(e => !e.allDay);

  return (
    <aside className="drawer">
      <div className="drawer-head">
        <div>
          <div className="drawer-dow">{DOW_LONG[dowMon(date)]}</div>
          <div className="drawer-date">
            <span className="drawer-day">{date.getDate()}</span>
            <span className="drawer-month">{MONTH_NAMES[date.getMonth()]}</span>
          </div>
        </div>
        <div className="drawer-nav">
          <button onClick={() => onJump(keyOf(addDays(date, -1)))} aria-label="Previous day">‹</button>
          <button onClick={() => onJump(keyOf(addDays(date, 1)))} aria-label="Next day">›</button>
        </div>
      </div>

      <button className="drawer-add" onClick={() => window.openEventEditor({ defaultDate: dateKey })}>
        + Add event on this day
      </button>

      {allDay.length > 0 && (
        <section className="drawer-section">
          <h4 className="drawer-section-title">All day</h4>
          <ul className="drawer-allday">
            {allDay.map((e) => {
              const c = cats[e.cat];
              const range = e.endDate
                ? `${parseKey(e.date).getDate()} ${MONTH_SHORT[parseKey(e.date).getMonth()]} – ${parseKey(e.endDate).getDate()} ${MONTH_SHORT[parseKey(e.endDate).getMonth()]}`
                : null;
              return (
                <li key={e.id} className="drawer-allday-item" style={{ background: c.soft, color: c.ink, cursor: "pointer" }}
                    onClick={() => window.openEventEditor({ initial: e })}>
                  <span className="dot" style={{ background: c.dot }} />
                  <span className="t">{e.title}</span>
                  {range && <span className="range">{range}</span>}
                </li>
              );
            })}
          </ul>
        </section>
      )}

      <section className="drawer-section drawer-schedule">
        <h4 className="drawer-section-title">Schedule</h4>
        {timed.length === 0 && allDay.length === 0 && (
          <div className="drawer-empty">Nothing booked. A clear day.</div>
        )}
        {timed.length > 0 && (
          <ul className="drawer-timed">
            {timed.map((e) => {
              const c = cats[e.cat];
              return (
                <li key={e.id} className="drawer-timed-item" style={{ cursor: "pointer" }}
                    onClick={() => window.openEventEditor({ initial: e })}>
                  <div className="dt-times">
                    <div className="dt-start">{e.start}</div>
                    <div className="dt-end">{e.end}</div>
                  </div>
                  <div className="dt-bar" style={{ background: c.dot }} />
                  <div className="dt-body">
                    <div className="dt-title">{e.title}</div>
                    <div className="dt-cat" style={{ color: c.ink }}>{cats[e.cat].label}</div>
                  </div>
                </li>
              );
            })}
          </ul>
        )}
      </section>

      <section className="drawer-section">
        <h4 className="drawer-section-title">Habits</h4>
        <div className="drawer-habits">
          {habits.map((h) => {
            const done = habitState.done(h.id, dateKey);
            return (
              <button
                type="button"
                key={h.id}
                className={`habit-pill ${done ? "done" : ""}`}
                onClick={() => habitState.toggle(h.id, dateKey)}
                aria-pressed={done}
              >
                <span className="habit-mark" style={{ background: done ? h.color : "transparent", borderColor: h.color }} />
                <span className="habit-label">{h.label}</span>
              </button>
            );
          })}
        </div>
      </section>
    </aside>
  );
}

// ─────────────────────────────────────────────────────────────────────
// Quick-capture: parses crude natural language → preview chip
function QuickCapture({ onAdd }) {
  const [text, setText] = useState("");
  const [preview, setPreview] = useState(null);

  function parse(s) {
    if (!s.trim()) return null;
    const lower = s.toLowerCase();
    let date = new Date(); // "today" baseline = real today
    date = new Date(date.getFullYear(), date.getMonth(), date.getDate());
    if (lower.includes("tomorrow") || lower.includes("tmrw")) date = addDays(date, 1);
    if (lower.includes("monday")) date = nextWeekday(date, 0);
    if (lower.includes("tuesday")) date = nextWeekday(date, 1);
    if (lower.includes("wednesday")) date = nextWeekday(date, 2);
    if (lower.includes("thursday")) date = nextWeekday(date, 3);
    if (lower.includes("friday")) date = nextWeekday(date, 4);
    if (lower.includes("saturday")) date = nextWeekday(date, 5);
    if (lower.includes("sunday")) date = nextWeekday(date, 6);

    const timeMatch = s.match(/(\d{1,2})(?::(\d{2}))?\s*(am|pm)?/i);
    let start = null;
    if (timeMatch) {
      let h = parseInt(timeMatch[1], 10);
      const m = timeMatch[2] ? parseInt(timeMatch[2], 10) : 0;
      const ap = (timeMatch[3] || "").toLowerCase();
      if (ap === "pm" && h < 12) h += 12;
      if (ap === "am" && h === 12) h = 0;
      start = `${String(h).padStart(2,"0")}:${String(m).padStart(2,"0")}`;
    }

    let cat = "personal";
    if (/\b(meet|sync|review|standup|1:1|interview)\b/i.test(s)) cat = "work";
    if (/\b(gym|run|yoga|physio|therapy)\b/i.test(s)) cat = "health";
    if (/\b(flight|train|airport|hotel)\b/i.test(s)) cat = "travel";
    if (/\b(mum|dad|sister|family)\b/i.test(s)) cat = "family";
    if (/\b(drinks|dinner|lunch|pub|party)\b/i.test(s)) cat = "social";
    if (/\b(dentist|doctor|renew|admin)\b/i.test(s)) cat = "admin";

    let title = s.replace(/\b(today|tomorrow|tmrw|monday|tuesday|wednesday|thursday|friday|saturday|sunday)\b/gi, "")
                 .replace(/\b\d{1,2}(?::\d{2})?\s*(am|pm)?\b/gi, "")
                 .replace(/\bat\b/gi, "")
                 .trim();
    if (!title) title = "New event";

    return { dateKey: keyOf(date), start, title, cat };
  }

  function nextWeekday(from, targetMon) {
    const cur = dowMon(from);
    let diff = targetMon - cur;
    if (diff <= 0) diff += 7;
    return addDays(from, diff);
  }

  useEffect(() => { setPreview(parse(text)); }, [text]);

  return (
    <div className="quick-capture">
      <div className="qc-row">
        <span className="qc-prefix">＋</span>
        <input
          value={text}
          onChange={(e) => setText(e.target.value)}
          placeholder="lunch tmrw 1pm with Sam"
          className="qc-input"
          onKeyDown={(e) => {
            if (e.key === "Enter" && preview) {
              onAdd(preview);
              setText("");
            }
          }}
        />
        <kbd className="qc-kbd">↵</kbd>
      </div>
      {preview && (
        <div className="qc-preview">
          <span className="qc-preview-dot" style={{ background: window.CALENDAR_DATA.CATEGORIES[preview.cat].dot }} />
          <span className="qc-preview-title">{preview.title}</span>
          <span className="qc-preview-meta">
            {fmtLong(parseKey(preview.dateKey))}{preview.start ? ` · ${preview.start}` : ""}
          </span>
        </div>
      )}
    </div>
  );
}

window.DesktopBits = { MiniMonth, MonthBlock, DayDrawer, QuickCapture };
