/* global React */

function ScheduleScreen({ tweaks, onReload, onRefresh }) {
  const { SCHEDULE, GROUPS, TEACHERS, TEACHER_FULL, ROOMS, DAY_NAMES, DAY_SHORT, UNSCHEDULED, CONFLICTS, TYPE_KEYS, isPending } = window.SCHED_DATA;
  const [committing, setCommitting] = useState(false);
  const [dropTarget, setDropTarget] = useState(null);
  const [startingEdit, setStartingEdit] = useState(false);
  const [editingLesson, setEditingLesson] = useState(null);
  const [editingUnscheduled, setEditingUnscheduled] = useState(null);
  async function startEditMode() {
    if (isPending) { setShowPanel(true); if (onRefresh) onRefresh(); return; }
    setStartingEdit(true);
    try {
      await window.API.post("/api/schedule/start-edit", {});
      await window.API.reloadAfterStartEdit();
      if (onRefresh) onRefresh();
    } catch (e) {
      alert("Ошибка: " + e.message);
      setStartingEdit(false);
      return;
    }
    setStartingEdit(false);
    setShowPanel(true);
  }

  function cancelEdit() {
    window.SCHED_DATA = Object.assign({}, window.SCHED_DATA, { isPending: false });
    if (onRefresh) onRefresh();
  }

  async function handleDropData(dragData, day, shift, lessonNumber) {
    setDropTarget(null);
    try {
      if (dragData.type === "slot") {
        if (dragData.day === day && dragData.shift === shift && dragData.lessonNumber === lessonNumber) return;
        const result = await window.API.post("/api/schedule/pending/move-slot", {
          lesson_id: dragData.lessonId,
          from_day: dragData.day,
          from_shift: dragData.shift,
          from_lesson: dragData.lessonNumber,
          to_day: day,
          to_shift: shift,
          to_lesson: lessonNumber,
        });
        window.API.applyMoveResponse(dragData.lessonId, dragData.day, dragData.shift, dragData.lessonNumber, day, shift, lessonNumber, result);
        if (onRefresh) onRefresh();
      } else if (dragData.type === "unscheduled") {
        const slots = await window.API.get(
          `/api/schedule/pending/find-slots?lesson_id=${dragData.lessonId}&day_of_week=-1&shift=-1&lesson_number=-1`
        );
        const match = slots.find(s => s.day_of_week === day && s.shift === shift && s.lesson_number === lessonNumber);
        if (!match) { alert("Нет свободной аудитории в этом слоте"); return; }
        const result = await window.API.post("/api/schedule/pending/add-slot", {
          lesson_id: dragData.lessonId,
          day_of_week: day,
          shift: shift,
          lesson_number: lessonNumber,
          room_id: match.room_id,
        });
        await window.API.reloadScheduleAfterAdd(result);
        if (onRefresh) onRefresh();
      }
    } catch (e) {
      alert("Ошибка: " + e.message);
    }
  }

  async function handleCommit() {
    setCommitting(true);
    try {
      await window.API.post("/api/schedule/commit", {});
      if (onReload) await onReload();
    } catch (e) {
      alert("Ошибка сохранения: " + e.message);
    } finally {
      setCommitting(false);
    }
  }

  const [viewMode, setViewMode] = useState("groups");
  const [layoutMode, setLayoutMode] = useState("single");
  const [entity, setEntity] = useState(() => GROUPS[0] || "");
  const [search, setSearch] = useState("");
  const [courseFilter, setCourseFilter] = useState("all");
  const [langFilter, setLangFilter] = useState("all");
  const [panelTab, setPanelTab] = useState("unscheduled");
  const [showPanel, setShowPanel] = useState(isPending);

  const entityList = useMemo(() => {
    if (viewMode === "groups") return GROUPS;
    if (viewMode === "teachers") return TEACHERS;
    return ROOMS.map(r => r.id);
  }, [viewMode, GROUPS, TEACHERS, ROOMS]);

  const groupLangMap = useMemo(() => {
    const m = {};
    SCHEDULE.forEach(s => { if (s.primary && s.language) m[s.primary] = s.language; });
    return m;
  }, [SCHEDULE]);

  const availableLangs = useMemo(() => {
    const s = new Set(Object.values(groupLangMap));
    return [...s].sort();
  }, [groupLangMap]);

  const filteredEntities = useMemo(() => {
    const s = search.trim().toLowerCase();
    let list = entityList;
    if (s) list = list.filter(e => e.toLowerCase().includes(s));
    if (viewMode === "groups" && courseFilter !== "all") {
      list = list.filter(e => e.includes(`-${courseFilter}`));
    }
    if (viewMode === "groups" && langFilter !== "all") {
      list = list.filter(e => groupLangMap[e] === langFilter);
    }
    return list;
  }, [entityList, search, viewMode, courseFilter, langFilter, groupLangMap]);

  const rows = useMemo(() => {
    if (viewMode === "groups") return SCHEDULE.filter(s => s.primary === entity || s.groups.includes(entity));
    if (viewMode === "teachers") return SCHEDULE.filter(s => s.teacher === entity);
    return SCHEDULE.filter(s => s.room === entity);
  }, [viewMode, entity, SCHEDULE]);

  // Build grid
  const days = [0, 1, 2, 3, 4, 5];
  const slotMap = new Map();
  for (const r of rows) {
    const k = `${r.day}|${r.shift}|${r.lessonNumber}`;
    if (!slotMap.has(k)) slotMap.set(k, []);
    slotMap.get(k).push(r);
  }

  const conflictKeys = useMemo(() => {
    const s = new Set();
    for (const c of CONFLICTS) {
      s.add(`${c.slotA[0]}|${c.slotA[1]}|${c.slotA[2]}`);
      s.add(`${c.slotB[0]}|${c.slotB[1]}|${c.slotB[2]}`);
    }
    return s;
  }, [CONFLICTS]);

  const conflictLessonSet = useMemo(() => {
    const s = new Set();
    for (const c of CONFLICTS) {
      if (c.lessonAId != null) s.add(`${c.lessonAId}|${c.slotA[0]}|${c.slotA[1]}|${c.slotA[2]}`);
      if (c.lessonBId != null) s.add(`${c.lessonBId}|${c.slotB[0]}|${c.slotB[1]}|${c.slotB[2]}`);
    }
    return s;
  }, [CONFLICTS]);

  // Use unified lesson slots 1..5 per shift. Build rows: (shift, lesson).
  const slotRows = [
    { shift: 1, ln: 1, time: "09:00" },
    { shift: 1, ln: 2, time: "10:00" },
    { shift: 1, ln: 3, time: "11:00" },
    { shift: 1, ln: 4, time: "12:00" },
    { shift: 1, ln: 5, time: "13:00" },
    { shift: 2, ln: 1, time: "14:00" },
    { shift: 2, ln: 2, time: "15:00" },
    { shift: 2, ln: 3, time: "16:00" },
    { shift: 2, ln: 4, time: "17:00" },
    { shift: 2, ln: 5, time: "18:00" },
  ];

  return (
    <div style={{ display: "flex", flex: 1, minHeight: 0 }}>
      {/* Left rail: entity list */}
      <aside style={{
        width: 280,
        borderRight: "1px solid var(--line)",
        background: "var(--paper)",
        display: "flex",
        flexDirection: "column",
        flexShrink: 0,
      }}>
        <div style={{ padding: "18px 20px 14px", borderBottom: "1px solid var(--line-soft)" }}>
          <div style={{ fontFamily: "var(--font-mono)", fontSize: 10, color: "var(--ink-3)", letterSpacing: "0.08em", textTransform: "uppercase", marginBottom: 8 }}>— ВЫБОР</div>
          <div style={{ display: "flex", background: "var(--surface)", border: "1px solid var(--line-strong)", borderRadius: 6, padding: 2 }}>
            {[
              { v: "groups", l: "Группы" },
              { v: "teachers", l: "Препод." },
              { v: "rooms", l: "Ауд." },
            ].map(o => (
              <button key={o.v} onClick={() => { setViewMode(o.v); setEntity((o.v === "groups" ? GROUPS : o.v === "teachers" ? TEACHERS : ROOMS.map(r => r.id))[0]); }}
                style={{
                  flex: 1, padding: "6px 0", fontSize: 12,
                  fontWeight: viewMode === o.v ? 600 : 500,
                  background: viewMode === o.v ? "var(--ink)" : "transparent",
                  color: viewMode === o.v ? "var(--paper)" : "var(--ink-3)",
                  borderRadius: 4,
                  transition: "all 0.12s",
                }}>{o.l}</button>
            ))}
          </div>
        </div>

        <div style={{ padding: "12px 20px", borderBottom: "1px solid var(--line-soft)" }}>
          <div style={{ position: "relative" }}>
            <Icon name="search" size={14} />
            <input className="input" placeholder="Поиск..." value={search} onChange={e => setSearch(e.target.value)}
              style={{ paddingLeft: 32, width: "100%", height: 32, fontSize: 12 }} />
            <div style={{ position: "absolute", left: 10, top: 9, color: "var(--ink-4)", pointerEvents: "none" }}>
              <Icon name="search" size={14} />
            </div>
          </div>
          {viewMode === "groups" && (
            <>
              <div style={{ display: "flex", gap: 4, marginTop: 8 }}>
                {["all", "1", "2", "3", "4"].map(c => (
                  <button key={c} onClick={() => setCourseFilter(c)}
                    style={{
                      flex: 1, padding: "4px 0", fontSize: 11,
                      border: "1px solid " + (courseFilter === c ? "var(--accent)" : "var(--line-strong)"),
                      background: courseFilter === c ? "var(--accent-soft)" : "transparent",
                      color: courseFilter === c ? "var(--accent)" : "var(--ink-3)",
                      borderRadius: 4,
                      fontWeight: 500,
                    }}>{c === "all" ? "все" : `${c} курс`}</button>
                ))}
              </div>
              {availableLangs.length > 1 && (
                <div style={{ display: "flex", gap: 4, marginTop: 4 }}>
                  {["all", ...availableLangs].map(l => (
                    <button key={l} onClick={() => setLangFilter(l)}
                      style={{
                        flex: 1, padding: "4px 0", fontSize: 11,
                        border: "1px solid " + (langFilter === l ? "var(--accent)" : "var(--line-strong)"),
                        background: langFilter === l ? "var(--accent-soft)" : "transparent",
                        color: langFilter === l ? "var(--accent)" : "var(--ink-3)",
                        borderRadius: 4,
                        fontWeight: 500,
                        textTransform: "capitalize",
                      }}>{l === "all" ? "все" : l}</button>
                  ))}
                </div>
              )}
            </>
          )}
        </div>

        <div style={{ flex: 1, overflowY: "auto", padding: "8px 0" }}>
          {filteredEntities.map(e => {
            const count = SCHEDULE.filter(s =>
              viewMode === "groups" ? s.primary === e :
              viewMode === "teachers" ? s.teacher === e :
              s.room === e
            ).length;
            return (
              <button key={e} onClick={() => setEntity(e)}
                style={{
                  display: "flex",
                  alignItems: "center",
                  justifyContent: "space-between",
                  width: "100%",
                  padding: "7px 20px",
                  fontSize: 13,
                  textAlign: "left",
                  background: entity === e ? "var(--surface)" : "transparent",
                  borderLeft: entity === e ? "2px solid var(--accent)" : "2px solid transparent",
                  color: entity === e ? "var(--ink)" : "var(--ink-2)",
                  fontWeight: entity === e ? 600 : 400,
                }}>
                <span>{e}</span>
                <span style={{ fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--ink-4)" }}>{count}</span>
              </button>
            );
          })}
        </div>

        <div style={{ padding: "12px 20px", borderTop: "1px solid var(--line-soft)", fontSize: 11, color: "var(--ink-3)", display: "flex", justifyContent: "space-between", fontFamily: "var(--font-mono)" }}>
          <span>{filteredEntities.length} / {entityList.length}</span>
          <span>↑↓ для выбора</span>
        </div>
      </aside>

      {/* Main grid area */}
      <main style={{ flex: 1, display: "flex", flexDirection: "column", minWidth: 0 }}>
        {/* Toolbar */}
        <div style={{
          display: "flex", alignItems: "center", gap: 16,
          padding: "14px 28px",
          borderBottom: "1px solid var(--line)",
          background: "var(--paper)",
        }}>
          <div>
            <div style={{ fontFamily: "var(--font-mono)", fontSize: 10, color: "var(--ink-3)", letterSpacing: "0.08em" }}>
              {layoutMode === "matrix"
                ? (viewMode === "groups" ? "ВСЕ ГРУППЫ" : viewMode === "teachers" ? "ВСЕ ПРЕПОДАВАТЕЛИ" : "ВСЕ АУДИТОРИИ")
                : (viewMode === "groups" ? "ГРУППА" : viewMode === "teachers" ? "ПРЕПОДАВАТЕЛЬ" : "АУДИТОРИЯ")}
            </div>
            <div style={{ fontFamily: "var(--font-serif)", fontSize: 26, lineHeight: 1 }}>
              {layoutMode === "matrix"
                ? `Сводная — ${filteredEntities.length}`
                : entity}
            </div>
          </div>

          <div style={{ marginLeft: "auto", display: "flex", alignItems: "center", gap: 8 }}>
            <div style={{ display: "flex", background: "var(--surface)", border: "1px solid var(--line-strong)", borderRadius: 6, padding: 2 }}>
              {[
                { v: "single", icon: "list", label: "Один" },
                { v: "matrix", icon: "grid", label: "Все" },
              ].map(o => (
                <button key={o.v} onClick={() => setLayoutMode(o.v)}
                  title={o.v === "single" ? "Подробный вид" : "Матрица всех сразу"}
                  style={{
                    display: "inline-flex", alignItems: "center", gap: 6,
                    padding: "5px 10px", fontSize: 12,
                    fontWeight: layoutMode === o.v ? 600 : 500,
                    background: layoutMode === o.v ? "var(--ink)" : "transparent",
                    color: layoutMode === o.v ? "var(--paper)" : "var(--ink-3)",
                    borderRadius: 4,
                  }}>
                  <Icon name={o.icon} size={12} />{o.label}
                </button>
              ))}
            </div>
            {(() => {
              const base = isPending ? "/api/export/pending" : "/api/export";
              const exportPath = viewMode === "teachers"
                ? `${base}/teachers`
                : viewMode === "rooms"
                  ? `${base}/template`
                  : `${base}/groups`;
              const exportLabel = viewMode === "teachers" ? "Преподаватели" : viewMode === "rooms" ? "Шаблон" : "Группы";
              const entitiesQS = filteredEntities.map(e => `entities=${encodeURIComponent(e)}`).join("&");
              const exportHref = `${window.API_BASE}${exportPath}?token=${window.API_TOKEN}&${entitiesQS}`;
              return isPending ? (
                <>
                  <span className="badge badge--warn"><Icon name="edit" size={10} /> ЧЕРНОВИК</span>
                  <a href={exportHref} className="btn btn--ghost" target="_blank" style={{ display: "inline-flex", alignItems: "center", gap: 6 }}>
                    <Icon name="download" size={14} /> {exportLabel}
                  </a>
                  <button className="btn btn--ghost" onClick={cancelEdit}>Отменить</button>
                  <button className="btn btn--primary" onClick={handleCommit} disabled={committing}>
                    <Icon name="check" size={14} /> {committing ? "Сохранение…" : "Сохранить расписание"}
                  </button>
                </>
              ) : (
                <>
                  <a href={exportHref} className="btn btn--ghost" target="_blank" style={{ display: "inline-flex", alignItems: "center", gap: 6 }}>
                    <Icon name="download" size={14} /> {exportLabel}
                  </a>
                  <button className="btn btn--ghost" onClick={startEditMode} disabled={startingEdit}>
                    <Icon name="edit" size={14} /> {startingEdit ? "Загрузка…" : "Редактировать"}
                  </button>
                </>
              );
            })()}
          </div>
        </div>

        {/* Grid */}
        <div style={{ flex: 1, overflow: "auto", padding: "20px 28px 28px", background: "var(--canvas)" }}>
          <div style={{
            background: "var(--surface)",
            border: "1px solid var(--line)",
            borderRadius: "var(--radius-lg)",
            overflow: "hidden",
            boxShadow: "var(--shadow-sm)",
          }}>
            {layoutMode === "single" ? (
              <ScheduleGrid
                days={days}
                slotRows={slotRows}
                slotMap={slotMap}
                conflictKeys={isPending ? conflictKeys : new Set()}
                editMode={isPending}
                tweaks={tweaks}
                canDrag={isPending}
                dropTarget={dropTarget}
                onDragEnter={(key) => setDropTarget(key)}
                onDragLeave={() => setDropTarget(null)}
                onDrop={handleDropData}
                onOpenLesson={isPending ? (lesson) => setEditingLesson(lesson) : null}
                conflictLessonSet={conflictLessonSet}
              />
            ) : (
              <MatrixGrid
                viewMode={viewMode}
                entities={filteredEntities}
                slotRows={slotRows}
                schedule={SCHEDULE}
                editMode={isPending}
                tweaks={tweaks}
                onDrop={isPending ? handleDropData : null}
                onOpenLesson={isPending ? (lesson) => setEditingLesson(lesson) : null}
                conflictLessonSet={isPending ? conflictLessonSet : null}
              />
            )}
          </div>

          {/* Legend */}
          <div style={{ display: "flex", gap: 20, alignItems: "center", padding: "18px 6px 0", fontSize: 11, color: "var(--ink-3)", fontFamily: "var(--font-mono)" }}>
            <span style={{ letterSpacing: "0.08em" }}>ЛЕГЕНДА</span>
            <LessonType type="Лекция" /> <LessonType type="Практика" /> <LessonType type="Лаборатория" /> <LessonType type="Семинар" />
            {isPending && (
              <>
                <span className="statusBar__sep" style={{ height: 14 }}/>
                <span style={{ display: "inline-flex", alignItems: "center", gap: 6 }}>
                  <span style={{ width: 10, height: 10, borderRadius: 2, background: "var(--danger-soft)", border: "1px solid var(--danger)" }}/>
                  конфликт
                </span>
                <span style={{ display: "inline-flex", alignItems: "center", gap: 6 }}>
                  <span style={{ width: 10, height: 10, borderRadius: 2, background: "var(--canvas)", border: "1px dashed var(--line-strong)" }}/>
                  пусто — перетащить
                </span>
              </>
            )}
          </div>
        </div>
      </main>

      {editingLesson && (
        <LessonEditModal
          lesson={editingLesson}
          conflicts={CONFLICTS.filter(c => c.lessonAId === editingLesson.lessonDbId || c.lessonBId === editingLesson.lessonDbId)}
          onClose={() => setEditingLesson(null)}
          onMoved={(result, lessonId, fromDay, fromShift, fromLesson, toDay, toShift, toLesson) => {
          setEditingLesson(null);
          window.API.applyMoveResponse(lessonId, fromDay, fromShift, fromLesson, toDay, toShift, toLesson, result);
          if (onRefresh) onRefresh();
        }}
        onDeleted={(result, lessonId, day, shift, lessonNumber) => {
          setEditingLesson(null);
          window.API.applyDeleteResponse(lessonId, day, shift, lessonNumber, result);
          if (onRefresh) onRefresh();
        }}
        />
      )}
      {editingUnscheduled && (
        <UnscheduledModal
          lesson={editingUnscheduled}
          onClose={() => setEditingUnscheduled(null)}
          onPlaced={async (result) => {
          setEditingUnscheduled(null);
          await window.API.reloadScheduleAfterAdd(result);
          if (onRefresh) onRefresh();
        }}
        />
      )}

      {/* Right panel: unscheduled + conflicts */}
      {isPending && showPanel && (
        <aside style={{
          width: 340,
          borderLeft: "1px solid var(--line)",
          background: "var(--paper)",
          display: "flex",
          flexDirection: "column",
          flexShrink: 0,
        }}>
          <div style={{ display: "flex", borderBottom: "1px solid var(--line)" }}>
            {[
              { id: "unscheduled", l: "Незапланированы", c: UNSCHEDULED.length, tone: "warn" },
              { id: "conflicts", l: "Конфликты", c: CONFLICTS.length, tone: "danger" },
            ].map(t => (
              <button key={t.id} onClick={() => setPanelTab(t.id)}
                style={{
                  flex: 1, padding: "14px 16px",
                  background: panelTab === t.id ? "var(--surface)" : "transparent",
                  borderBottom: panelTab === t.id ? "2px solid var(--accent)" : "2px solid transparent",
                  fontSize: 12, fontWeight: 600,
                  color: panelTab === t.id ? "var(--ink)" : "var(--ink-3)",
                  textAlign: "left",
                  marginBottom: "-1px",
                }}>
                {t.l}
                <span className={`badge badge--${t.tone}`} style={{ marginLeft: 8 }}>{t.c}</span>
              </button>
            ))}
          </div>

          <div style={{ flex: 1, overflowY: "auto", padding: "10px 0" }}>
            {panelTab === "unscheduled" ? (
              UNSCHEDULED.map(u => (
                <div key={u.dbId}
                  draggable
                  onDragStart={(e) => {
                    e.dataTransfer.effectAllowed = "copy";
                    e.dataTransfer.setData("text/plain", JSON.stringify({
                      type: "unscheduled",
                      lessonId: u.dbId,
                    }));
                  }}
                  onClick={() => setEditingUnscheduled(u)}
                  style={{
                    margin: "6px 14px",
                    padding: "12px 14px",
                    background: "var(--surface)",
                    border: "1px solid var(--line-strong)",
                    borderRadius: 6,
                    cursor: "pointer",
                  }}>
                  <div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 8, marginBottom: 6 }}>
                    <div style={{ fontSize: 13, fontWeight: 600, flex: 1 }}>{u.discipline}</div>
                    <LessonType type={u.lessonType} short />
                  </div>
                  <div style={{ fontSize: 11, color: "var(--ink-3)", marginBottom: 8 }}>
                    {u.groups.join(", ")}
                  </div>
                  <div style={{ display: "flex", gap: 12, fontSize: 11, fontFamily: "var(--font-mono)", color: "var(--ink-3)" }}>
                    <span>{u.remainingSlots} слот{u.remainingSlots > 1 ? "а" : ""}</span>
                    <span>{u.remainingHours} ч.</span>
                  </div>
                </div>
              ))
            ) : (
              CONFLICTS.map((c, i) => (
                <div key={i} style={{
                  margin: "6px 14px",
                  padding: "12px 14px",
                  background: "var(--surface)",
                  border: "1px solid var(--danger)",
                  borderLeft: "3px solid var(--danger)",
                  borderRadius: 6,
                }}>
                  <div style={{ display: "flex", alignItems: "center", gap: 6, marginBottom: 6 }}>
                    <Icon name="alert" size={12} />
                    <span style={{ fontSize: 11, fontWeight: 600, color: "var(--danger)", textTransform: "uppercase", letterSpacing: "0.06em", fontFamily: "var(--font-mono)" }}>
                      {c.type === "teacher" ? "Преподаватель" : c.type === "room" ? "Аудитория" : "Группа"}
                    </span>
                  </div>
                  <div style={{ fontSize: 12, lineHeight: 1.4, marginBottom: 8 }}>{c.description}</div>
                  <div style={{ fontSize: 11, fontFamily: "var(--font-mono)", color: "var(--ink-3)" }}>
                    {DAY_SHORT[c.slotA[0]]} · {c.slotA[1] === 1 ? "утро" : "день"} · пара {c.slotA[2]}
                  </div>
                  <button className="btn btn--ghost btn--sm" style={{ marginTop: 10 }} onClick={() => {
                    const m = c.description.match(/^(Группа|Преподаватель|Подгруппа\/группа)\s+([^:,]+)/);
                    if (m) {
                      const isTeacher = m[1] === "Преподаватель";
                      const name = m[2].trim();
                      setViewMode(isTeacher ? "teachers" : "groups");
                      setEntity(name);
                    }
                  }}>
                    Перейти →
                  </button>
                </div>
              ))
            )}
          </div>
        </aside>
      )}
    </div>
  );
}

function ScheduleGrid({ days, slotRows, slotMap, conflictKeys, editMode, tweaks, canDrag, dropTarget, onDragEnter, onDragLeave, onDrop, onOpenLesson, conflictLessonSet }) {
  const { DAY_NAMES, DAY_SHORT } = window.SCHED_DATA;

  // days-cols layout: days as columns, time slots as rows
  return (
    <div style={{ display: "grid", gridTemplateColumns: `72px repeat(${days.length}, 1fr)` }}>
      {/* Header row */}
      <div style={{ borderBottom: "1px solid var(--line)", borderRight: "1px solid var(--line-soft)", background: "var(--paper)" }}/>
      {days.map(d => (
        <div key={d} style={{
          padding: "12px 14px",
          borderBottom: "1px solid var(--line)",
          borderRight: d < days.length - 1 ? "1px solid var(--line-soft)" : "none",
          background: "var(--paper)",
        }}>
          <div style={{ fontFamily: "var(--font-mono)", fontSize: 10, color: "var(--ink-3)", letterSpacing: "0.08em" }}>{DAY_SHORT[d].toUpperCase()}</div>
          <div style={{ fontSize: 14, fontWeight: 600, marginTop: 2 }}>{DAY_NAMES[d]}</div>
          <div style={{ fontFamily: "var(--font-mono)", fontSize: 10, color: "var(--ink-4)", marginTop: 1 }}>{String(20 + d).padStart(2, "0")}.04</div>
        </div>
      ))}

      {/* Slot rows */}
      {slotRows.map((sr, sIdx) => {
        const isShiftBreak = sIdx > 0 && slotRows[sIdx - 1].shift !== sr.shift;
        return (
          <Fragment key={`${sr.shift}-${sr.ln}`}>
            <div style={{
              padding: "10px 10px 10px 14px",
              borderTop: isShiftBreak ? "2px solid var(--line-strong)" : "1px solid var(--line-soft)",
              borderRight: "1px solid var(--line-soft)",
              background: "var(--paper)",
              display: "flex",
              flexDirection: "column",
              justifyContent: "center",
            }}>
              <div style={{ fontFamily: "var(--font-mono)", fontSize: 14, fontWeight: 500, fontVariantNumeric: "tabular-nums" }}>{sr.time}</div>
              <div style={{ fontSize: 10, color: "var(--ink-4)", fontFamily: "var(--font-mono)" }}>
                {sr.shift === 1 ? "I" : "II"}·{sr.ln}
              </div>
            </div>
            {days.map(d => {
              const k = `${d}|${sr.shift}|${sr.ln}`;
              const lessons = slotMap.get(k) || [];
              const hasConflict = lessons.some(l =>
                conflictLessonSet && conflictLessonSet.has(`${l.lessonDbId}|${l.day}|${l.shift}|${l.lessonNumber}`)
              );
              return (
                <SlotCell key={k}
                  lessons={lessons}
                  hasConflict={hasConflict}
                  isShiftBreak={isShiftBreak}
                  isLast={d === days.length - 1}
                  editMode={editMode}
                  tweaks={tweaks}
                  canDrag={canDrag}
                  isDropTarget={dropTarget === k}
                  onDragEnter={() => onDragEnter(k)}
                  onDragLeave={onDragLeave}
                  onDrop={(dragData) => onDrop(dragData, d, sr.shift, sr.ln)}
                  onOpenLesson={onOpenLesson}
                  conflictLessonSet={conflictLessonSet}
                />
              );
            })}
          </Fragment>
        );
      })}
    </div>
  );
}

function SlotCell({ lessons, hasConflict, isShiftBreak, isLast, editMode, tweaks, canDrag, isDropTarget, onDragEnter, onDragLeave, onDrop, onOpenLesson, conflictLessonSet }) {
  const empty = lessons.length === 0;
  return (
    <div
      style={{
        position: "relative",
        minHeight: tweaks.density === "compact" ? 68 : 84,
        borderTop: isShiftBreak ? "2px solid var(--line-strong)" : "1px solid var(--line-soft)",
        borderRight: isLast ? "none" : "1px solid var(--line-soft)",
        padding: 5,
        background: isDropTarget ? "var(--accent-soft)" : hasConflict ? "var(--danger-soft)" : "transparent",
        outline: isDropTarget ? "2px dashed var(--accent)" : "none",
        outlineOffset: -2,
        transition: "background 0.1s",
      }}
      onDragOver={canDrag ? (e) => { e.preventDefault(); e.dataTransfer.dropEffect = "move"; } : undefined}
      onDragEnter={canDrag ? (e) => { e.preventDefault(); onDragEnter(); } : undefined}
      onDragLeave={canDrag ? (e) => { if (!e.currentTarget.contains(e.relatedTarget)) onDragLeave(); } : undefined}
      onDrop={canDrag ? (e) => { e.preventDefault(); try { onDrop(JSON.parse(e.dataTransfer.getData("text/plain"))); } catch {} } : undefined}
    >
      {empty && (editMode || (canDrag && isDropTarget)) && (
        <div style={{
          position: "absolute", inset: 4,
          border: `1px dashed ${isDropTarget ? "var(--accent)" : "var(--line-strong)"}`,
          borderRadius: 4,
          display: "grid", placeItems: "center",
          fontSize: 11,
          color: isDropTarget ? "var(--accent)" : "var(--ink-4)",
          fontFamily: "var(--font-mono)",
        }}>+</div>
      )}
      {lessons.map((l, i) => {
        const lc = conflictLessonSet ? conflictLessonSet.has(`${l.lessonDbId}|${l.day}|${l.shift}|${l.lessonNumber}`) : false;
        return <LessonCard key={i} lesson={l} hasConflict={lc} tweaks={tweaks} canDrag={canDrag} onOpen={onOpenLesson} />;
      })}
    </div>
  );
}

function LessonCard({ lesson, hasConflict, tweaks, canDrag, onOpen }) {
  const tkey = window.SCHED_DATA.TYPE_KEYS[lesson.lessonType] || "other";
  const subgroups = lesson.groups.filter(g => g !== lesson.primary);
  const subLabel = subgroups.length > 0
    ? subgroups.map(g => {
        const prefix = lesson.primary + "/";
        return g.startsWith(prefix) ? g.slice(prefix.length) : g;
      }).join(", ")
    : null;
  return (
    <div
      draggable={canDrag}
      onClick={onOpen ? () => onOpen(lesson) : undefined}
      onDragStart={canDrag ? (e) => {
        e.dataTransfer.effectAllowed = "move";
        e.dataTransfer.setData("text/plain", JSON.stringify({
          type: "slot",
          lessonId: lesson.lessonDbId,
          day: lesson.day,
          shift: lesson.shift,
          lessonNumber: lesson.lessonNumber,
        }));
      } : undefined}
      style={{
        background: `var(--${tkey}-bg)`,
        borderLeft: `3px solid var(--${tkey}-border)`,
        borderRadius: 4,
        padding: "6px 8px 7px",
        marginBottom: 3,
        cursor: canDrag ? "grab" : onOpen ? "pointer" : "default",
        outline: hasConflict ? "1px solid var(--danger)" : "none",
      }}>
      <div style={{
        fontSize: 12, fontWeight: 600,
        color: `var(--${tkey}-text)`,
        lineHeight: 1.25,
        marginBottom: 3,
        display: "-webkit-box",
        WebkitLineClamp: 2,
        WebkitBoxOrient: "vertical",
        overflow: "hidden",
      }}>{lesson.discipline}</div>
      <div style={{ display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap", fontSize: 10, color: "var(--ink-3)", fontFamily: "var(--font-mono)" }}>
        {tweaks.showType && <LessonType type={lesson.lessonType} short />}
        {subLabel && (
          <span style={{
            background: `var(--${tkey}-border)`,
            color: "var(--paper)",
            borderRadius: 3,
            padding: "0px 4px",
            fontSize: 9,
            fontWeight: 700,
            letterSpacing: "0.04em",
          }}>пгр.{subLabel}</span>
        )}
        {tweaks.showRoom && <span>{lesson.room}</span>}
        {tweaks.showTeacher && <span style={{ flex: 1, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{lesson.teacherFull || lesson.teacher}</span>}
      </div>
    </div>
  );
}

function MatrixGrid({ viewMode, entities, slotRows, schedule, editMode, tweaks, onDrop, onOpenLesson, conflictLessonSet }) {
  const { DAY_NAMES, DAY_SHORT, TYPE_KEYS } = window.SCHED_DATA;
  const [activeDay, setActiveDay] = useState(0);
  const [dropTarget, setDropTarget] = useState(null);

  const map = useMemo(() => {
    const m = new Map();
    for (const s of schedule) {
      if (s.day !== activeDay) continue;
      const key = viewMode === "groups" ? s.primary : viewMode === "teachers" ? s.teacher : s.room;
      if (!entities.includes(key)) continue;
      const sk = `${s.shift}|${s.lessonNumber}`;
      if (!m.has(key)) m.set(key, new Map());
      const inner = m.get(key);
      if (!inner.has(sk)) inner.set(sk, []);
      inner.get(sk).push(s);
    }
    return m;
  }, [schedule, entities, viewMode, activeDay]);

  const colWidth = 130;

  return (
    <div>
      <div style={{ display: "flex", borderBottom: "1px solid var(--line)", padding: "10px 14px", gap: 4, background: "var(--paper)" }}>
        {[0,1,2,3,4,5].map(d => (
          <button key={d} onClick={() => setActiveDay(d)}
            style={{
              padding: "6px 14px", fontSize: 12,
              fontWeight: activeDay === d ? 600 : 500,
              background: activeDay === d ? "var(--ink)" : "transparent",
              color: activeDay === d ? "var(--paper)" : "var(--ink-3)",
              borderRadius: 4,
            }}>
            <span style={{ fontFamily: "var(--font-mono)", marginRight: 6, opacity: 0.7 }}>{DAY_SHORT[d].toUpperCase()}</span>
            {DAY_NAMES[d]}
          </button>
        ))}
        <div style={{ marginLeft: "auto", fontSize: 11, color: "var(--ink-3)", fontFamily: "var(--font-mono)", alignSelf: "center" }}>
          {entities.length} {viewMode === "groups" ? "групп" : viewMode === "teachers" ? "преподавателей" : "аудиторий"} × 10 слотов
        </div>
      </div>
      <div style={{ overflow: "auto", maxHeight: "calc(100vh - 320px)" }}>
        <div style={{ display: "grid", gridTemplateColumns: `74px repeat(${entities.length}, ${colWidth}px)`, minWidth: "fit-content" }}>
          <div style={{ position: "sticky", left: 0, top: 0, zIndex: 3, background: "var(--paper)", borderRight: "1px solid var(--line)", borderBottom: "1px solid var(--line)" }}/>
          {entities.map((e, i) => (
            <div key={e} style={{
              position: "sticky", top: 0, zIndex: 2,
              padding: "10px 8px",
              borderBottom: "1px solid var(--line)",
              borderRight: i < entities.length - 1 ? "1px solid var(--line-soft)" : "none",
              background: "var(--paper)",
              fontSize: 11, fontWeight: 600,
              textAlign: "center",
              overflow: "hidden",
              textOverflow: "ellipsis",
              whiteSpace: "nowrap",
            }}>{e}</div>
          ))}
          {slotRows.map((sr, sIdx) => {
            const isShiftBreak = sIdx > 0 && slotRows[sIdx - 1].shift !== sr.shift;
            return (
              <Fragment key={`${sr.shift}-${sr.ln}`}>
                <div style={{
                  position: "sticky", left: 0, zIndex: 1,
                  padding: "8px 10px",
                  background: "var(--paper)",
                  borderRight: "1px solid var(--line)",
                  borderTop: isShiftBreak ? "2px solid var(--line-strong)" : "1px solid var(--line-soft)",
                  display: "flex", flexDirection: "column", justifyContent: "center",
                }}>
                  <div style={{ fontFamily: "var(--font-mono)", fontSize: 12, fontWeight: 500, fontVariantNumeric: "tabular-nums" }}>{sr.time}</div>
                  <div style={{ fontSize: 9, color: "var(--ink-4)", fontFamily: "var(--font-mono)" }}>{sr.shift === 1 ? "I" : "II"}·{sr.ln}</div>
                </div>
                {entities.map((e, i) => {
                  const lessons = (map.get(e) || new Map()).get(`${sr.shift}|${sr.ln}`) || [];
                  const cellKey = `${activeDay}|${sr.shift}|${sr.ln}|${e}`;
                  const isDropTarget = dropTarget === cellKey;
                  const hasConflict = conflictLessonSet && lessons.some(l =>
                    conflictLessonSet.has(`${l.lessonDbId}|${l.day}|${l.shift}|${l.lessonNumber}`)
                  );
                  return (
                    <div key={cellKey}
                      style={{
                        borderTop: isShiftBreak ? "2px solid var(--line-strong)" : "1px solid var(--line-soft)",
                        borderRight: i < entities.length - 1 ? "1px solid var(--line-soft)" : "none",
                        minHeight: 56,
                        padding: 3,
                        background: isDropTarget ? "var(--accent-soft)" : hasConflict ? "var(--danger-soft)" : "transparent",
                        outline: isDropTarget ? "2px dashed var(--accent)" : "none",
                        outlineOffset: -2,
                        transition: "background 0.1s",
                      }}
                      onDragOver={onDrop ? (e) => { e.preventDefault(); e.dataTransfer.dropEffect = "move"; } : undefined}
                      onDragEnter={onDrop ? (e) => { e.preventDefault(); setDropTarget(cellKey); } : undefined}
                      onDragLeave={onDrop ? (e) => { if (!e.currentTarget.contains(e.relatedTarget)) setDropTarget(null); } : undefined}
                      onDrop={onDrop ? (e) => { e.preventDefault(); setDropTarget(null); try { onDrop(JSON.parse(e.dataTransfer.getData("text/plain")), activeDay, sr.shift, sr.ln); } catch {} } : undefined}
                    >
                      {lessons.length === 0 && editMode && isDropTarget && (
                        <div style={{
                          position: "absolute", inset: 2,
                          border: "1px dashed var(--accent)",
                          borderRadius: 3,
                          display: "grid", placeItems: "center",
                          fontSize: 10, color: "var(--accent)",
                          fontFamily: "var(--font-mono)",
                          pointerEvents: "none",
                        }}>+</div>
                      )}
                      {lessons.map((l, j) => {
                        const tkey = TYPE_KEYS[l.lessonType] || "other";
                        const hasLessonConflict = conflictLessonSet ? conflictLessonSet.has(`${l.lessonDbId}|${l.day}|${l.shift}|${l.lessonNumber}`) : false;
                        return (
                          <div key={j}
                            draggable={!!editMode}
                            onClick={onOpenLesson ? () => onOpenLesson(l) : undefined}
                            onDragStart={editMode ? (e) => {
                              e.dataTransfer.effectAllowed = "move";
                              e.dataTransfer.setData("text/plain", JSON.stringify({
                                type: "slot",
                                lessonId: l.lessonDbId,
                                day: l.day,
                                shift: l.shift,
                                lessonNumber: l.lessonNumber,
                              }));
                            } : undefined}
                            style={{
                              background: `var(--${tkey}-bg)`,
                              borderLeft: `2px solid var(--${tkey}-border)`,
                              borderRadius: 3,
                              padding: "3px 5px",
                              marginBottom: 2,
                              fontSize: 10,
                              lineHeight: 1.25,
                              color: `var(--${tkey}-text)`,
                              overflow: "hidden",
                              cursor: editMode ? "grab" : onOpenLesson ? "pointer" : "default",
                              outline: hasLessonConflict ? "1px solid var(--danger)" : "none",
                            }}>
                            <div style={{ fontWeight: 600, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{l.discipline}</div>
                            <div style={{ fontFamily: "var(--font-mono)", fontSize: 9, color: "var(--ink-3)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>
                              {l.room} · {l.teacherFull || l.teacher}
                            </div>
                          </div>
                        );
                      })}
                    </div>
                  );
                })}
              </Fragment>
            );
          })}
        </div>
      </div>
    </div>
  );
}

function LessonEditModal({ lesson, conflicts, onClose, onMoved, onDeleted }) {
  const { DAY_NAMES } = window.SCHED_DATA;
  const [loading, setLoading] = useState(false);
  const [slots, setSlots] = useState(null);
  const [selected, setSelected] = useState(null);
  const [moving, setMoving] = useState(false);
  const [deleting, setDeleting] = useState(false);

  async function deleteSlot() {
    if (!confirm("Удалить занятие из расписания?")) return;
    setDeleting(true);
    try {
      const result = await window.API.post("/api/schedule/pending/delete-slot", {
        lesson_id: lesson.lessonDbId,
        day_of_week: lesson.day,
        shift: lesson.shift,
        lesson_number: lesson.lessonNumber,
      });
      onDeleted(result, lesson.lessonDbId, lesson.day, lesson.shift, lesson.lessonNumber);
    } catch (e) {
      alert("Ошибка: " + e.message);
      setDeleting(false);
    }
  }

  async function findSlots() {
    setLoading(true);
    setSlots(null);
    setSelected(null);
    try {
      const res = await window.API.get(
        `/api/schedule/pending/find-slots?lesson_id=${lesson.lessonDbId}&day_of_week=${lesson.day}&shift=${lesson.shift}&lesson_number=${lesson.lessonNumber}`
      );
      setSlots(res);
    } catch {
      setSlots([]);
    } finally {
      setLoading(false);
    }
  }

  async function moveToSlot() {
    if (!selected) return;
    setMoving(true);
    try {
      const result = await window.API.post("/api/schedule/pending/move-slot", {
        lesson_id: lesson.lessonDbId,
        from_day: lesson.day,
        from_shift: lesson.shift,
        from_lesson: lesson.lessonNumber,
        to_day: selected.day_of_week,
        to_shift: selected.shift,
        to_lesson: selected.lesson_number,
        room_id: selected.room_id,
      });
      onMoved(result, lesson.lessonDbId, lesson.day, lesson.shift, lesson.lessonNumber, selected.day_of_week, selected.shift, selected.lesson_number);
    } catch (e) {
      alert("Ошибка: " + e.message);
      setMoving(false);
    }
  }

  return (
    <div
      onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}
      style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.45)", zIndex: 200, display: "grid", placeItems: "center", padding: 24 }}
    >
      <div style={{ background: "var(--paper)", borderRadius: 12, width: 460, maxHeight: "80vh", display: "flex", flexDirection: "column", boxShadow: "0 20px 60px rgba(0,0,0,0.25)" }}>
        <div style={{ padding: "22px 24px 18px", borderBottom: "1px solid var(--line)" }}>
          <div style={{ fontFamily: "var(--font-mono)", fontSize: 10, color: "var(--ink-3)", letterSpacing: "0.08em", marginBottom: 8 }}>
            {DAY_NAMES[lesson.day]} · {lesson.shift === 1 ? "I смена" : "II смена"} · пара {lesson.lessonNumber} · ауд. {lesson.room}
          </div>
          <div style={{ fontFamily: "var(--font-serif)", fontSize: 22, lineHeight: 1.2, marginBottom: 6 }}>{lesson.discipline}</div>
          <div style={{ fontSize: 13, color: "var(--ink-3)" }}>{lesson.teacherFull} · {lesson.groups.join(", ")}</div>
        </div>

        <div style={{ padding: "18px 24px", flex: 1, overflowY: "auto" }}>
          <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 14 }}>
            <div style={{ fontSize: 13, fontWeight: 600 }}>Найти свободный слот</div>
            <button className="btn btn--ghost btn--sm" onClick={findSlots} disabled={loading}>
              {loading ? "Поиск…" : "Найти"}
            </button>
          </div>

          {conflicts && conflicts.length > 0 && (
            <div style={{ marginBottom: 16, padding: "10px 14px", background: "var(--danger-soft)", border: "1px solid var(--danger)", borderRadius: 6 }}>
              <div style={{ fontSize: 11, fontWeight: 600, color: "var(--danger)", fontFamily: "var(--font-mono)", letterSpacing: "0.06em", marginBottom: 6 }}>КОНФЛИКТЫ</div>
              {conflicts.map((c, i) => (
                <div key={i} style={{ fontSize: 12, color: "var(--danger)", lineHeight: 1.5 }}>· {c.description}</div>
              ))}
            </div>
          )}

          {slots === null && (
            <div style={{ fontSize: 12, color: "var(--ink-4)", fontStyle: "italic" }}>
              Нажмите «Найти» чтобы показать доступные слоты
            </div>
          )}
          {slots !== null && slots.length === 0 && (
            <div style={{ fontSize: 13, color: "var(--ink-3)", textAlign: "center", padding: "16px 0" }}>
              Свободных слотов не найдено
            </div>
          )}
          {slots !== null && slots.length > 0 && (
            <div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
              {slots.map((s, i) => {
                const isSel = selected && selected.day_of_week === s.day_of_week && selected.shift === s.shift && selected.lesson_number === s.lesson_number;
                return (
                  <button key={i} onClick={() => setSelected(isSel ? null : s)}
                    style={{
                      display: "grid", gridTemplateColumns: "1fr auto auto",
                      alignItems: "center", gap: 12,
                      padding: "10px 14px", borderRadius: 6, textAlign: "left",
                      background: isSel ? "var(--accent-soft)" : "var(--surface)",
                      border: `1px solid ${isSel ? "var(--accent)" : "var(--line-strong)"}`,
                      transition: "all 0.1s",
                    }}>
                    <span style={{ fontSize: 13, fontWeight: 600 }}>{DAY_NAMES[s.day_of_week]}</span>
                    <span style={{ fontSize: 12, color: "var(--ink-3)", fontFamily: "var(--font-mono)", whiteSpace: "nowrap" }}>
                      {s.shift === 1 ? "I" : "II"} · п.{s.lesson_number}
                    </span>
                    <span style={{ fontSize: 12, color: "var(--ink-3)", fontFamily: "var(--font-mono)", whiteSpace: "nowrap" }}>
                      {s.room_id} · {s.building}
                    </span>
                  </button>
                );
              })}
            </div>
          )}
        </div>

        <div style={{ padding: "14px 24px", borderTop: "1px solid var(--line)", display: "flex", gap: 8 }}>
          <button className="btn btn--ghost" style={{ color: "var(--danger)", borderColor: "var(--danger)" }} onClick={deleteSlot} disabled={deleting}>
            <Icon name="x" size={14} /> {deleting ? "Удаление…" : "Удалить"}
          </button>
          <div style={{ flex: 1 }} />
          <button className="btn btn--ghost" onClick={onClose}>Закрыть</button>
          {selected && (
            <button className="btn btn--primary" onClick={moveToSlot} disabled={moving}>
              {moving ? "Перемещение…" : "Переместить"}
            </button>
          )}
        </div>
      </div>
    </div>
  );
}

function UnscheduledModal({ lesson, onClose, onPlaced }) {
  const { DAY_NAMES } = window.SCHED_DATA;
  const [loading, setLoading] = useState(false);
  const [slots, setSlots] = useState(null);
  const [selected, setSelected] = useState(null);
  const [placing, setPlacing] = useState(false);

  async function findSlots() {
    setLoading(true);
    setSlots(null);
    setSelected(null);
    try {
      const res = await window.API.get(
        `/api/schedule/pending/find-slots?lesson_id=${lesson.dbId}&day_of_week=-1&shift=-1&lesson_number=-1`
      );
      setSlots(res);
    } catch {
      setSlots([]);
    } finally {
      setLoading(false);
    }
  }

  async function placeInSlot() {
    if (!selected) return;
    setPlacing(true);
    try {
      const result = await window.API.post("/api/schedule/pending/add-slot", {
        lesson_id: lesson.dbId,
        day_of_week: selected.day_of_week,
        shift: selected.shift,
        lesson_number: selected.lesson_number,
        room_id: selected.room_id,
      });
      onPlaced(result);
    } catch (e) {
      alert("Ошибка: " + e.message);
      setPlacing(false);
    }
  }

  return (
    <div onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}
      style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.45)", zIndex: 200, display: "grid", placeItems: "center", padding: 24 }}>
      <div style={{ background: "var(--paper)", borderRadius: 12, width: 460, maxHeight: "80vh", display: "flex", flexDirection: "column", boxShadow: "0 20px 60px rgba(0,0,0,0.25)" }}>
        <div style={{ padding: "22px 24px 18px", borderBottom: "1px solid var(--line)" }}>
          <div style={{ fontFamily: "var(--font-mono)", fontSize: 10, color: "var(--warn)", letterSpacing: "0.08em", marginBottom: 8 }}>НЕ РАЗМЕЩЕНО · {lesson.remainingSlots} слот{lesson.remainingSlots > 1 ? "а" : ""}</div>
          <div style={{ fontFamily: "var(--font-serif)", fontSize: 22, lineHeight: 1.2, marginBottom: 6 }}>{lesson.discipline}</div>
          <div style={{ fontSize: 13, color: "var(--ink-3)" }}>{lesson.lessonType} · {lesson.groups.join(", ")}</div>
        </div>
        <div style={{ padding: "18px 24px", flex: 1, overflowY: "auto" }}>
          <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 14 }}>
            <div style={{ fontSize: 13, fontWeight: 600 }}>Найти свободный слот</div>
            <button className="btn btn--ghost btn--sm" onClick={findSlots} disabled={loading}>
              {loading ? "Поиск…" : "Найти"}
            </button>
          </div>
          {slots === null && <div style={{ fontSize: 12, color: "var(--ink-4)", fontStyle: "italic" }}>Нажмите «Найти» чтобы показать доступные слоты</div>}
          {slots !== null && slots.length === 0 && <div style={{ fontSize: 13, color: "var(--ink-3)", textAlign: "center", padding: "16px 0" }}>Свободных слотов не найдено</div>}
          {slots !== null && slots.length > 0 && (
            <div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
              {slots.map((s, i) => {
                const isSel = selected && selected.day_of_week === s.day_of_week && selected.shift === s.shift && selected.lesson_number === s.lesson_number;
                return (
                  <button key={i} onClick={() => setSelected(isSel ? null : s)}
                    style={{ display: "grid", gridTemplateColumns: "1fr auto auto", alignItems: "center", gap: 12, padding: "10px 14px", borderRadius: 6, textAlign: "left", background: isSel ? "var(--accent-soft)" : "var(--surface)", border: `1px solid ${isSel ? "var(--accent)" : "var(--line-strong)"}` }}>
                    <span style={{ fontSize: 13, fontWeight: 600 }}>{DAY_NAMES[s.day_of_week]}</span>
                    <span style={{ fontSize: 12, color: "var(--ink-3)", fontFamily: "var(--font-mono)", whiteSpace: "nowrap" }}>{s.shift === 1 ? "I" : "II"} · п.{s.lesson_number}</span>
                    <span style={{ fontSize: 12, color: "var(--ink-3)", fontFamily: "var(--font-mono)", whiteSpace: "nowrap" }}>{s.room_id} · {s.building}</span>
                  </button>
                );
              })}
            </div>
          )}
        </div>
        <div style={{ padding: "14px 24px", borderTop: "1px solid var(--line)", display: "flex", gap: 8, justifyContent: "flex-end" }}>
          <button className="btn btn--ghost" onClick={onClose}>Закрыть</button>
          {selected && <button className="btn btn--primary" onClick={placeInSlot} disabled={placing}>{placing ? "Размещение…" : "Разместить"}</button>}
        </div>
      </div>
    </div>
  );
}

window.ScheduleScreen = ScheduleScreen;
