import { useEffect, useMemo, useState } from "react";
import SectionCard from "../components/SectionCard";
import LookupModal from "../components/LookupModal";
import { api, downloadBinary, openBinary, printBinary } from "../lib/api";
import { useLocation } from "react-router-dom";




const meetingTypeOptions = [
  { value: "ordentlich", label: "Ordentlich" },
  { value: "ausserordentlich", label: "Außerordentlich" },
];

const statusOptions = [
  { value: "geplant", label: "Geplant" },
  { value: "ungeplant", label: "Ungeplant" },
  { value: "gestartet", label: "Gestartet" },
  { value: "beendet", label: "Beendet" },
];

const PAGE_SIZE = 25;

function initialForm() {
  return {
    meeting_number: "",
    title: "",
    meeting_type: "ordentlich",
    meeting_date: "",
    start_time: "",
    end_time: "",
    location: "",
    status: "geplant",
    protocol_text: "",
    committee_id: "",
    chair_user_id: "",
    secretary_user_id: "",
  };
}

function isMeetingLocked(row) {
  return row?.status === "gestartet" || row?.status === "beendet";
}

function formatDateTime(value) {
  if (!value) return "";
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return value;
  return date.toLocaleString("de-DE");
}

function formatFileSize(value) {
  const bytes = Number(value || 0);
  if (!bytes) return "";
  if (bytes < 1024) return `${bytes} B`;
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
}

function formatQuorum(value) {
  if (value === true) return "Ja";
  if (value === false) return "Nein";
  return "–";
}

function agendaStatusLabel(value) {
  const labels = {
    offen: "Offen",
    in_sitzung: "In Sitzung",
    rueckfrage: "Rückfrage",
    klaerung: "Klärung",
    erledigt: "Erledigt",
  };
  return labels[value] || value || "Offen";
}

function returnTypeLabel(value) {
  if (value === "klaerung") return "Klärung";
  if (value === "bemerkung") return "Bemerkung / Wiedervorlage";
  return "Rückfrage";
}

function AgendaAssignmentModal({
  meeting,
  data,
  onAssignExisting,
  onCreateAndAssign,
  onUnassign,
  onCreateFollowUp,
  onOpenReports,
  onOpenComments,
  onClose,
  loading,
}) {
  const assigned = data?.assigned || [];
  const unassigned = data?.unassigned || [];
  const locked = isMeetingLocked(meeting);
  const followUpLocked = meeting?.status === "beendet";

  const [newTitle, setNewTitle] = useState("");
  const [newDescription, setNewDescription] = useState("");
  const [newMinutes, setNewMinutes] = useState("");
  const [newCaseId, setNewCaseId] = useState("");
  const [filter, setFilter] = useState("");

  const loweredFilter = filter.trim().toLowerCase();
  const matchesFilter = (row) => {
    if (!loweredFilter) return true;
    return JSON.stringify(row).toLowerCase().includes(loweredFilter);
  };

  const filteredAssigned = assigned.filter(matchesFilter);
  const filteredUnassigned = unassigned.filter(matchesFilter);

  return (
    <div
      style={{
        position: "fixed",
        inset: 0,
        background: "rgba(15, 23, 42, 0.55)",
        display: "grid",
        placeItems: "center",
        zIndex: 999,
      }}
    >
      <div
        className="glass"
        style={{
          width: "min(1280px, 96vw)",
          maxHeight: "88vh",
          overflow: "auto",
          padding: 18,
          borderRadius: 20,
        }}
      >
        <div
          style={{
            display: "flex",
            justifyContent: "space-between",
            alignItems: "center",
            gap: 12,
            marginBottom: 14,
            flexWrap: "wrap",
          }}
        >
          <div>
            <h3 style={{ margin: 0 }}>TOPs für Sitzung</h3>
            <p style={{ margin: "6px 0 0 0", opacity: 0.75 }}>
              {meeting?.meeting_number} – {meeting?.title}
            </p>
            {locked ? (
              <p style={{ margin: "6px 0 0 0", color: "#b45309" }}>
                Diese Sitzung ist gesperrt. TOPs und zugehörige Berichte können angezeigt, aber nicht mehr geändert werden.
              </p>
            ) : null}
          </div>

          <div style={{ display: "flex", gap: 10, alignItems: "center", flexWrap: "wrap" }}>
            <input
              className="input search"
              placeholder="TOPs / Themen suchen..."
              value={filter}
              onChange={(e) => setFilter(e.target.value)}
            />
            <button className="btn secondary" type="button" onClick={onClose}>
              Schließen
            </button>
          </div>
        </div>

        <div className="page-grid" style={{ gridTemplateColumns: "1fr 1fr" }}>
          <SectionCard
            title="Bereits zugewiesene TOPs"
            subtitle="TOP-Nummern werden automatisch beim Hinzufügen vergeben. Zugehörige Berichte lassen sich direkt anzeigen oder nachdrucken."
          >
            <div className="table-wrap">
              <table className="table">
                <thead>
                  <tr>
                    <th>TOP</th>
                    <th>Vorgang</th>
                    <th>Titel</th>
                    <th>Min.</th>
                    <th>Status</th>
                    <th>Berichte</th>
                    <th>Kommentare</th>
                    <th></th>
                  </tr>
                </thead>
                <tbody>
                  {filteredAssigned.map((row) => (
                    <tr key={row.id}>
                      <td>{row.agenda_number}</td>
                      <td>{row.case_number || row.case_id || ""}</td>
                      <td>
                        {row.title}
                        {row.parent_agenda_item_id ? (
                          <>
                            <br />
                            <small>Folge von TOP {row.parent_agenda_number || row.parent_agenda_item_id}{row.follow_up_source_meeting_number ? ` · Sitzung ${row.follow_up_source_meeting_number}` : ""}</small>
                          </>
                        ) : null}
                      </td>
                      <td>{row.duration_minutes ?? ""}</td>
                      <td>{agendaStatusLabel(row.status || "in_sitzung")}</td>
                      <td>{row.report_count ?? 0}</td>
                      <td>{row.comment_count ?? 0}{row.protocol_comment_count ? ` / ${row.protocol_comment_count} im Protokoll` : ""}</td>
                      <td className="row-actions">
                        <button
                          className="mini-btn"
                          type="button"
                          onClick={() => onOpenReports(row)}
                        >
                          Berichte
                        </button>
                        <button
                          className="mini-btn"
                          type="button"
                          onClick={() => onOpenComments(row)}
                        >
                          Kommentare
                        </button>
                        <button
                          className="mini-btn"
                          type="button"
                          disabled={loading || followUpLocked}
                          onClick={() => onCreateFollowUp(row)}
                        >
                          Folge-TOP
                        </button>
                        <button
                          className="mini-btn danger"
                          type="button"
                          disabled={loading || locked}
                          onClick={() => onUnassign(row.id)}
                        >
                          Entfernen
                        </button>
                      </td>
                    </tr>
                  ))}
                  {!filteredAssigned.length ? (
                    <tr>
                      <td colSpan={8}>Keine TOPs zugewiesen</td>
                    </tr>
                  ) : null}
                </tbody>
              </table>
            </div>
          </SectionCard>

          <SectionCard
            title="TOP-Bestand hinzufügen"
            subtitle="Vorhandenen TOP auswählen oder direkt einen neuen TOP für diese Sitzung erzeugen."
          >
            <div className="table-wrap" style={{ marginBottom: 16 }}>
              <table className="table">
                <thead>
                  <tr>
                    <th>ID</th>
                    <th>Vorgang</th>
                    <th>Titel</th>
                    <th>Min.</th>
                    <th>Status</th>
                    <th>Berichte</th>
                    <th>Bemerkung</th>
                    <th></th>
                  </tr>
                </thead>
                <tbody>
                  {filteredUnassigned.map((row) => (
                    <tr key={row.id}>
                      <td>{row.id}</td>
                      <td>{row.case_number || row.case_id || ""}</td>
                      <td>
                        {row.title}
                        {row.parent_agenda_item_id ? (
                          <>
                            <br />
                            <small>Folge von TOP {row.parent_agenda_number || row.parent_agenda_item_id}{row.follow_up_source_meeting_number ? ` · Sitzung ${row.follow_up_source_meeting_number}` : ""}</small>
                          </>
                        ) : null}
                      </td>
                      <td>{row.duration_minutes ?? ""}</td>
                      <td>{agendaStatusLabel(row.status || "offen")}</td>
                      <td>{row.report_count ?? 0}</td>
                      <td>{row.follow_up_note || row.last_return_remark ? <small>{returnTypeLabel(row.follow_up_type || row.last_return_type)}: {row.follow_up_note || row.last_return_remark}</small> : ""}</td>
                      <td>
                        <button
                          className="mini-btn"
                          type="button"
                          disabled={loading || locked}
                          onClick={() => onAssignExisting(row.id)}
                        >
                          Hinzufügen
                        </button>
                      </td>
                    </tr>
                  ))}
                  {!filteredUnassigned.length ? (
                    <tr>
                      <td colSpan={8}>Keine freien TOPs vorhanden</td>
                    </tr>
                  ) : null}
                </tbody>
              </table>
            </div>

            <div className="form-grid">
              <label>
                <span>Neuer TOP-Titel</span>
                <input
                  className="input"
                  value={newTitle}
                  onChange={(e) => setNewTitle(e.target.value)}
                  disabled={locked}
                />
              </label>

              <label>
                <span>Vorgangs-ID optional</span>
                <input
                  className="input"
                  value={newCaseId}
                  onChange={(e) => setNewCaseId(e.target.value.replace(/[^\d]/g, ""))}
                  disabled={locked}
                />
              </label>

              <label>
                <span>Dauer in Minuten</span>
                <input
                  className="input"
                  type="number"
                  min="0"
                  max="600"
                  value={newMinutes}
                  onChange={(e) => setNewMinutes(e.target.value)}
                  disabled={locked}
                />
              </label>

              <label>
                <span>Beschreibung</span>
                <textarea
                  className="input textarea"
                  value={newDescription}
                  onChange={(e) => setNewDescription(e.target.value)}
                  disabled={locked}
                />
              </label>

              <button
                className="btn"
                type="button"
                disabled={loading || locked || !newTitle.trim()}
                onClick={() => {
                  onCreateAndAssign({
                    title: newTitle.trim(),
                    description: newDescription.trim() || null,
                    duration_minutes: newMinutes ? Number(newMinutes) : null,
                    case_id: newCaseId ? Number(newCaseId) : null,
                  });
                  setNewTitle("");
                  setNewDescription("");
                  setNewMinutes("");
                  setNewCaseId("");
                }}
              >
                Neuen TOP erzeugen und zuweisen
              </button>
            </div>
          </SectionCard>
        </div>
      </div>
    </div>
  );
}

function AgendaReportsModal({ open, data, onClose, onView, onDownload, onPrint, onPrintSummary }) {
  if (!open) return null;

  const agenda = data?.agenda_item || null;
  const reports = data?.reports || [];

  return (
    <div className="modal-backdrop">
      <div className="modal-panel" style={{ width: "min(1080px, 100%)" }}>
        <div className="modal-header">
          <div>
            <h3 style={{ margin: 0 }}>Berichte zu TOP {agenda?.agenda_number || ""}</h3>
            <p className="modal-subtitle">
              {agenda?.title || ""}
              {agenda?.case_number ? ` · Vorgang ${agenda.case_number}` : ""}
            </p>
          </div>
          <button className="modal-close" type="button" onClick={onClose} aria-label="Schließen">
            ×
          </button>
        </div>

        {agenda?.case_summary ? (
          <SectionCard
            title="Bericht / Sachverhalt"
            subtitle="Der Berichtstext des verknüpften Vorgangs kann direkt nachgedruckt werden."
            actions={<button className="btn secondary" type="button" onClick={() => onPrintSummary(agenda)}>Bericht drucken</button>}
          >
            <div style={{ whiteSpace: "pre-wrap", lineHeight: 1.5 }}>{agenda.case_summary}</div>
          </SectionCard>
        ) : null}

        <SectionCard
          title="Verknüpfte Dokumente"
          subtitle="Dokumente des TOP-Vorgangs und der Sitzung können angezeigt, heruntergeladen oder nachgedruckt werden."
        >
          <div className="table-wrap">
            <table className="table">
              <thead>
                <tr>
                  <th>ID</th>
                  <th>Dokument-Nr.</th>
                  <th>Titel</th>
                  <th>Art</th>
                  <th>Datei</th>
                  <th>Größe</th>
                  <th>Hochgeladen</th>
                  <th>Von</th>
                  <th>Aktionen</th>
                </tr>
              </thead>
              <tbody>
                {reports.map((row) => (
                  <tr key={row.id}>
                    <td>{row.id}</td>
                    <td>{row.document_number || ""}</td>
                    <td>{row.title}</td>
                    <td>{row.document_type || ""}</td>
                    <td>{row.file_name || ""}</td>
                    <td>{formatFileSize(row.size_bytes)}</td>
                    <td>{formatDateTime(row.uploaded_at)}</td>
                    <td>{row.uploaded_by_name || ""}</td>
                    <td className="row-actions">
                      <button className="mini-btn" type="button" onClick={() => onView(row)}>Anzeigen</button>
                      <button className="mini-btn" type="button" onClick={() => onPrint(row)}>Nachdrucken</button>
                      <button className="mini-btn" type="button" onClick={() => onDownload(row)}>Download</button>
                    </td>
                  </tr>
                ))}
                {!reports.length ? (
                  <tr>
                    <td colSpan={9}>Keine Berichte oder Dokumente zu diesem TOP gefunden</td>
                  </tr>
                ) : null}
              </tbody>
            </table>
          </div>
        </SectionCard>
      </div>
    </div>
  );
}

function AgendaCommentsModal({ open, data, loading, onClose, onCreate, onUpdate, onDelete }) {
  const [newText, setNewText] = useState("");
  const [newVisibility, setNewVisibility] = useState("intern");
  const [newIncludeInProtocol, setNewIncludeInProtocol] = useState(false);
  const [editingId, setEditingId] = useState("");
  const [editText, setEditText] = useState("");
  const [editVisibility, setEditVisibility] = useState("intern");
  const [editIncludeInProtocol, setEditIncludeInProtocol] = useState(false);

  useEffect(() => {
    if (!open) {
      setNewText("");
      setNewVisibility("intern");
      setNewIncludeInProtocol(false);
      setEditingId("");
    }
  }, [open]);

  if (!open) return null;

  const agenda = data?.agenda_item || null;
  const comments = data?.comments || [];
  const disabled = data?.meeting?.status === "beendet";

  function startEdit(row) {
    setEditingId(String(row.id));
    setEditText(row.comment_text || "");
    setEditVisibility(row.visibility || "intern");
    setEditIncludeInProtocol(Boolean(row.include_in_protocol));
  }

  async function submitNew(event) {
    event.preventDefault();
    if (!newText.trim()) return;
    await onCreate({
      comment_text: newText.trim(),
      visibility: newVisibility,
      include_in_protocol: newIncludeInProtocol,
    });
    setNewText("");
    setNewVisibility("intern");
    setNewIncludeInProtocol(false);
  }

  async function submitEdit(row) {
    if (!editText.trim()) return;
    await onUpdate(row, {
      comment_text: editText.trim(),
      visibility: editVisibility,
      include_in_protocol: editIncludeInProtocol,
    });
    setEditingId("");
  }

  return (
    <div className="modal-backdrop">
      <div className="modal-panel" style={{ width: "min(1080px, 100%)" }}>
        <div className="modal-header">
          <div>
            <h3 style={{ margin: 0 }}>Kommentare zu TOP {agenda?.agenda_number || ""}</h3>
            <p className="modal-subtitle">
              {agenda?.title || ""}
              {disabled ? " · Sitzung beendet" : ""}
            </p>
          </div>
          <button className="modal-close" type="button" onClick={onClose} aria-label="Schließen">
            ×
          </button>
        </div>

        {disabled ? (
          <div className="alert" style={{ marginBottom: 14 }}>
            Diese Sitzung ist beendet. Kommentare können angezeigt, aber nicht mehr geändert werden.
          </div>
        ) : null}

        <SectionCard
          title="Neuer Kommentar"
          subtitle="Mit dem Schalter „ins Protokoll“ wird der Kommentar beim Erzeugen des Sitzungsprotokolls beim jeweiligen TOP ausgegeben."
        >
          <form className="form-grid" onSubmit={submitNew}>
            <label>
              <span>Kommentar</span>
              <textarea
                className="input textarea"
                value={newText}
                onChange={(event) => setNewText(event.target.value)}
                disabled={disabled || loading}
              />
            </label>
            <div style={{ display: "flex", gap: 14, alignItems: "center", flexWrap: "wrap" }}>
              <label style={{ minWidth: 220 }}>
                <span>Sichtbarkeit</span>
                <select
                  className="input"
                  value={newVisibility}
                  onChange={(event) => setNewVisibility(event.target.value)}
                  disabled={disabled || loading}
                >
                  <option value="intern">Intern</option>
                  <option value="vertraulich">Vertraulich</option>
                </select>
              </label>
              <label className="switch-line">
                <input
                  type="checkbox"
                  checked={newIncludeInProtocol}
                  onChange={(event) => setNewIncludeInProtocol(event.target.checked)}
                  disabled={disabled || loading}
                />
                <span>Ins Sitzungsprotokoll übernehmen</span>
              </label>
              <button className="btn" type="submit" disabled={disabled || loading || !newText.trim()}>
                Kommentar hinzufügen
              </button>
            </div>
          </form>
        </SectionCard>

        <SectionCard title="Bestehende Kommentare" subtitle="Kommentare können direkt hier bearbeitet und für das Protokoll ein- oder ausgeschaltet werden.">
          <div className="table-wrap">
            <table className="table">
              <thead>
                <tr>
                  <th>Kommentar</th>
                  <th>Kommentar von</th>
                  <th>Sichtbarkeit</th>
                  <th>Protokoll</th>
                  <th>Aktionen</th>
                </tr>
              </thead>
              <tbody>
                {comments.map((row) => {
                  const editing = String(row.id) === editingId;
                  return (
                    <tr key={row.id}>
                      <td style={{ minWidth: 320 }}>
                        {editing ? (
                          <textarea
                            className="input textarea"
                            value={editText}
                            onChange={(event) => setEditText(event.target.value)}
                            disabled={loading}
                          />
                        ) : (
                          <div style={{ whiteSpace: "pre-wrap" }}>{row.comment_text}</div>
                        )}
                        <small>{formatDateTime(row.created_at)}</small>
                      </td>
                      <td>Kommentar von: {row.author_name || row.author_user_id || "unbekannt"}</td>
                      <td>
                        {editing ? (
                          <select
                            className="input"
                            value={editVisibility}
                            onChange={(event) => setEditVisibility(event.target.value)}
                            disabled={loading}
                          >
                            <option value="intern">Intern</option>
                            <option value="vertraulich">Vertraulich</option>
                          </select>
                        ) : row.visibility === "vertraulich" ? "Vertraulich" : "Intern"}
                      </td>
                      <td>
                        {editing ? (
                          <label className="switch-line">
                            <input
                              type="checkbox"
                              checked={editIncludeInProtocol}
                              onChange={(event) => setEditIncludeInProtocol(event.target.checked)}
                              disabled={loading}
                            />
                            <span>Übernehmen</span>
                          </label>
                        ) : row.include_in_protocol ? "Ja" : "Nein"}
                      </td>
                      <td className="row-actions">
                        {editing ? (
                          <>
                            <button className="mini-btn" type="button" onClick={() => submitEdit(row)} disabled={loading || !editText.trim()}>
                              Speichern
                            </button>
                            <button className="mini-btn" type="button" onClick={() => setEditingId("")} disabled={loading}>
                              Abbrechen
                            </button>
                          </>
                        ) : (
                          <>
                            <button className="mini-btn" type="button" onClick={() => startEdit(row)} disabled={disabled || loading}>
                              Bearbeiten
                            </button>
                            <button
                              className="mini-btn"
                              type="button"
                              disabled={disabled || loading}
                              onClick={() => onUpdate(row, { include_in_protocol: !row.include_in_protocol })}
                            >
                              {row.include_in_protocol ? "Nicht ins Protokoll" : "Ins Protokoll"}
                            </button>
                            <button className="mini-btn danger" type="button" onClick={() => onDelete(row)} disabled={disabled || loading}>
                              Löschen
                            </button>
                          </>
                        )}
                      </td>
                    </tr>
                  );
                })}
                {!comments.length ? (
                  <tr>
                    <td colSpan={5}>Noch keine Kommentare zu diesem TOP vorhanden.</td>
                  </tr>
                ) : null}
              </tbody>
            </table>
          </div>
        </SectionCard>
      </div>
    </div>
  );
}

function FollowUpAgendaItemModal({ open, meeting, agendaItem, loading, onClose, onSubmit }) {
  const [returnType, setReturnType] = useState("rueckfrage");
  const [remark, setRemark] = useState("");
  const [includeInProtocol, setIncludeInProtocol] = useState(true);

  useEffect(() => {
    if (open) {
      setReturnType("rueckfrage");
      setRemark("");
      setIncludeInProtocol(true);
    }
  }, [open, agendaItem?.id]);

  if (!open || !agendaItem) return null;

  async function submit(event) {
    event.preventDefault();
    if (!remark.trim()) return;
    await onSubmit({
      return_type: returnType,
      remark: remark.trim(),
      include_in_protocol: includeInProtocol,
    });
  }

  return (
    <div className="modal-backdrop">
      <div className="modal-panel" style={{ width: "min(760px, 100%)" }}>
        <div className="modal-header">
          <div>
            <h3 style={{ margin: 0 }}>Folge-TOP für Rückfrage / Klärung / Wiedervorlage anlegen</h3>
            <p className="modal-subtitle">
              TOP {agendaItem.agenda_number || agendaItem.id} – {agendaItem.title}
              {meeting?.meeting_number ? ` · Sitzung ${meeting.meeting_number}` : ""}
            </p>
          </div>
          <button className="modal-close" type="button" onClick={onClose} aria-label="Schließen" disabled={loading}>
            ×
          </button>
        </div>

        <div className="alert" style={{ marginBottom: 14 }}>
          Der ursprüngliche TOP bleibt in dieser Sitzung erhalten. Zusätzlich wird ein neuer verknüpfter Folge-TOP im TOP-Bestand angelegt.
        </div>

        <form className="form-grid" onSubmit={submit}>
          <label>
            <span>Art</span>
            <select className="input" value={returnType} onChange={(event) => setReturnType(event.target.value)} disabled={loading}>
              <option value="rueckfrage">Rückfrage</option>
              <option value="klaerung">Klärung</option>
              <option value="bemerkung">Bemerkung / Wiedervorlage</option>
            </select>
          </label>

          <label>
            <span>Bemerkung / Rückfrage / Klärung</span>
            <textarea
              className="input textarea"
              required
              value={remark}
              onChange={(event) => setRemark(event.target.value)}
              placeholder="Was muss vor erneuter Behandlung geklärt oder bearbeitet werden?"
              disabled={loading}
            />
          </label>

          <label className="switch-line">
            <input
              type="checkbox"
              checked={includeInProtocol}
              onChange={(event) => setIncludeInProtocol(event.target.checked)}
              disabled={loading}
            />
            <span>Bemerkung und Folge-TOP im Sitzungsprotokoll erwähnen</span>
          </label>

          <div className="row-actions" style={{ justifyContent: "flex-end" }}>
            <button className="btn secondary" type="button" onClick={onClose} disabled={loading}>
              Abbrechen
            </button>
            <button className="btn" type="submit" disabled={loading || !remark.trim()}>
              Folge-TOP anlegen
            </button>
          </div>
        </form>
      </div>
    </div>
  );
}

function MeetingFormFields({
  form,
  setForm,
  committees,
  committeeUsers,
  handleCommitteeChange,
  setLookup,
  disabled,
}) {
  return (
    <>
      <label>
        <span>Sitzungsnummer</span>
        <input className="input" value={form.meeting_number} readOnly placeholder="Wird automatisch generiert" />
      </label>

      <label>
        <span>Titel</span>
        <input
          className="input"
          value={form.title}
          onChange={(e) => setForm({ ...form, title: e.target.value })}
          disabled={disabled}
        />
      </label>

      <label>
        <span>Art</span>
        <select
          className="input"
          value={form.meeting_type}
          onChange={(e) => setForm({ ...form, meeting_type: e.target.value })}
          disabled={disabled}
        >
          {meetingTypeOptions.map((item) => (
            <option key={item.value} value={item.value}>
              {item.label}
            </option>
          ))}
        </select>
      </label>

      <label>
        <span>Sitzungsdatum</span>
        <input
          className="input"
          type="date"
          value={form.meeting_date}
          onChange={(e) => setForm({ ...form, meeting_date: e.target.value })}
          disabled={disabled}
        />
      </label>

      <label>
        <span>Startzeit</span>
        <input
          className="input"
          type="time"
          value={form.start_time}
          onChange={(e) => setForm({ ...form, start_time: e.target.value })}
          disabled={disabled}
        />
      </label>

      <label>
        <span>Endzeit</span>
        <input
          className="input"
          type="time"
          value={form.end_time}
          onChange={(e) => setForm({ ...form, end_time: e.target.value })}
          disabled={disabled}
        />
      </label>

      <label>
        <span>Ort</span>
        <input
          className="input"
          value={form.location}
          onChange={(e) => setForm({ ...form, location: e.target.value })}
          disabled={disabled}
        />
      </label>

      <label>
        <span>Status</span>
        <select
          className="input"
          value={form.status}
          onChange={(e) => setForm({ ...form, status: e.target.value })}
          disabled={disabled}
        >
          {statusOptions.map((item) => (
            <option key={item.value} value={item.value}>
              {item.label}
            </option>
          ))}
        </select>
      </label>

      <label>
        <span>Ausschuss</span>
        <select
          className="input"
          value={form.committee_id}
          onChange={(e) => handleCommitteeChange(e.target.value)}
          disabled={disabled}
        >
          <option value="">Bitte auswählen</option>
          {committees.map((committee) => (
            <option key={committee.id} value={committee.id}>
              {committee.name}
            </option>
          ))}
        </select>
      </label>

      {[
        ["chair_user_id", "Leitung User-ID"],
        ["secretary_user_id", "Schriftführung User-ID"],
      ].map(([field, label]) => {
        const user = committeeUsers.find((row) => String(row.id) === String(form[field]));
        return (
          <label key={field}>
            <span>{label}</span>
            <div style={{ display: "flex", gap: 8 }}>
              <input className="input" value={form[field]} readOnly />
              <button
                className="btn secondary"
                type="button"
                onClick={() => setLookup(field)}
                disabled={disabled}
              >
                Auswählen
              </button>
              <button
                className="btn secondary"
                type="button"
                onClick={() => setForm({ ...form, [field]: "" })}
                disabled={disabled}
              >
                Leeren
              </button>
            </div>
            <small>{user ? `${user.full_name} (${user.email})` : "Kein Benutzer ausgewählt"}</small>
          </label>
        );
      })}

      <label>
        <span>Protokoll</span>
        <textarea
          className="input textarea"
          value={form.protocol_text}
          onChange={(e) => setForm({ ...form, protocol_text: e.target.value })}
          disabled={disabled}
        />
      </label>
    </>
  );
}

function MeetingEditorModal({
  open,
  selected,
  form,
  setForm,
  committees,
  committeeUsers,
  handleCommitteeChange,
  setLookup,
  onClose,
  onSubmit,
  error,
  lookupOpen,
}) {
  if (!open) return null;

  const disabled = selected ? isMeetingLocked(selected) : false;

  return (
    <div
      className="modal-backdrop"
      onClick={(e) => {
        if (lookupOpen) return;
        if (e.target === e.currentTarget) onClose();
      }}
    >
      <div className="modal-panel" onClick={(e) => e.stopPropagation()}>
        <div className="modal-header">
          <div>
            <h2 style={{ margin: 0 }}>{selected ? "Sitzung bearbeiten" : "Neue Sitzung anlegen"}</h2>
            <p className="modal-subtitle">
              {selected
                ? "Gleiche Funktion wie beim Anlegen. Die Sitzungsnummer ist bereits vergeben."
                : "Die Sitzungsnummer wird beim Speichern automatisch erzeugt."}
            </p>
          </div>
          <button className="modal-close" type="button" onClick={onClose} aria-label="Schließen">
            ×
          </button>
        </div>

        {error ? <div className="alert error">{error}</div> : null}
        {disabled ? <div className="alert">Diese Sitzung ist gesperrt und kann nicht mehr bearbeitet werden.</div> : null}

        <form className="form-grid" onSubmit={onSubmit}>
          <MeetingFormFields
            form={form}
            setForm={setForm}
            committees={committees}
            committeeUsers={committeeUsers}
            handleCommitteeChange={handleCommitteeChange}
            setLookup={setLookup}
            disabled={disabled}
          />

          <div style={{ display: "flex", justifyContent: "flex-end", gap: 10, gridColumn: "1 / -1" }}>
            <button className="btn secondary" type="button" onClick={onClose}>
              Abbrechen
            </button>
            <button className="btn" type="submit" disabled={disabled}>
              {selected ? "Speichern" : "Erstellen"}
            </button>
          </div>
        </form>
      </div>
    </div>
  );
}

function StartMeetingModal({ meeting, loading, onAnswer, onClose }) {
  if (!meeting) return null;

  return (
    <div
      className="modal-backdrop"
      onClick={(e) => {
        if (!loading && e.target === e.currentTarget) onClose();
      }}
    >
      <div className="modal-panel" style={{ width: "min(560px, 100%)" }} onClick={(e) => e.stopPropagation()}>
        <div className="modal-header">
          <div>
            <h2 style={{ margin: 0 }}>Sitzung starten</h2>
            <p className="modal-subtitle">
              {meeting.meeting_number} – {meeting.title}
            </p>
          </div>
          <button className="modal-close" type="button" onClick={onClose} disabled={loading} aria-label="Schließen">
            ×
          </button>
        </div>

        <div className="alert" style={{ marginBottom: 16 }}>
          Ist die Sitzung beschlussfähig?
        </div>

        <p style={{ marginTop: 0, opacity: 0.8 }}>
          Die Antwort wird gespeichert und am Anfang des automatisch erzeugten Protokolls ausgegeben.
        </p>

        <div style={{ display: "flex", justifyContent: "flex-end", gap: 10, flexWrap: "wrap" }}>
          <button className="btn secondary" type="button" onClick={onClose} disabled={loading}>
            Abbrechen
          </button>
          <button className="btn secondary" type="button" onClick={() => onAnswer(false)} disabled={loading}>
            Nein
          </button>
          <button className="btn" type="button" onClick={() => onAnswer(true)} disabled={loading}>
            Ja
          </button>
        </div>
      </div>
    </div>
  );
}

export default function MeetingsPage() {
  const [rows, setRows] = useState([]);
  const [committees, setCommittees] = useState([]);
  const [users, setUsers] = useState([]);
  const [selected, setSelected] = useState(null);
  const [form, setForm] = useState(initialForm());
  const [query, setQuery] = useState("");
  const [message, setMessage] = useState("");
  const [error, setError] = useState("");
  const [modalError, setModalError] = useState("");
  const [lookup, setLookup] = useState(null);
  const [agendaModal, setAgendaModal] = useState(null);
  const [agendaLoading, setAgendaLoading] = useState(false);
  const [reportModal, setReportModal] = useState(null);
  const [reportLoading, setReportLoading] = useState(false);
  const [commentModal, setCommentModal] = useState(null);
  const [commentLoading, setCommentLoading] = useState(false);
  const [followUpAgendaItem, setFollowUpAgendaItem] = useState(null);
  const [showEnded, setShowEnded] = useState(false);
  const [page, setPage] = useState(1);
  const [isMeetingModalOpen, setIsMeetingModalOpen] = useState(false);
  const [startModalMeeting, setStartModalMeeting] = useState(null);
  const [startLoading, setStartLoading] = useState(false);
  const location = useLocation();

useEffect(() => {
  const openId = new URLSearchParams(location.search).get("open");
  if (!openId || !rows.length) return;

  const row = rows.find((item) => String(item.id) === String(openId));
  if (row && !isMeetingLocked(row)) {
    openEditModal(row);
  }
}, [location.search, rows]);
  
  const [meta, setMeta] = useState({
    total: 0,
    page: 1,
    page_size: PAGE_SIZE,
    total_pages: 1,
  });

  async function load({
    nextPage = page,
    nextShowEnded = showEnded,
    nextQuery = query,
  } = {}) {
    setError("");
    try {
      const params = new URLSearchParams({
        show_ended: nextShowEnded ? "true" : "false",
        page: String(nextPage),
        page_size: String(PAGE_SIZE),
      });

      if (String(nextQuery || "").trim()) {
        params.set("q", nextQuery.trim());
      }

      const [meetings, committeeData, userData] = await Promise.all([
        api.get(`/meetings?${params.toString()}`),
        api.get("/committees"),
        api.get("/users"),
      ]);

      setRows(Array.isArray(meetings?.items) ? meetings.items : []);
      setMeta({
        total: meetings?.total ?? 0,
        page: meetings?.page ?? 1,
        page_size: meetings?.page_size ?? PAGE_SIZE,
        total_pages: meetings?.total_pages ?? 1,
      });

      setCommittees(Array.isArray(committeeData) ? committeeData : []);
      setUsers(Array.isArray(userData) ? userData.filter((row) => row.is_active !== false) : []);
    } catch (err) {
      setError(err.message);
    }
  }

  useEffect(() => {
    load();
  }, [page, showEnded]);

  useEffect(() => {
    const timer = setTimeout(() => {
      load({ nextPage: 1, nextQuery: query });
      setPage(1);
    }, 250);
    return () => clearTimeout(timer);
  }, [query]);

  const committeeUsers = useMemo(() => {
    if (!form.committee_id) return users;
    return users.filter((row) => !row.committee_id || String(row.committee_id) === String(form.committee_id));
  }, [users, form.committee_id]);

  function findCommittee(id) {
    return committees.find((row) => String(row.id) === String(id));
  }

  function openEditModal(row) {
    if (isMeetingLocked(row)) return;

    setSelected(row);
    setForm({
      meeting_number: row.meeting_number ?? "",
      title: row.title ?? "",
      meeting_type: row.meeting_type ?? "ordentlich",
      meeting_date: row.meeting_date ?? "",
      start_time: row.start_time ?? "",
      end_time: row.end_time ?? "",
      location: row.location ?? "",
      status: row.status ?? "geplant",
      protocol_text: row.protocol_text ?? "",
      committee_id: row.committee_id ? String(row.committee_id) : "",
      chair_user_id: row.chair_user_id ? String(row.chair_user_id) : "",
      secretary_user_id: row.secretary_user_id ? String(row.secretary_user_id) : "",
    });
    setLookup(null);
    setMessage("");
    setError("");
    setModalError("");
    setIsMeetingModalOpen(true);
  }

  function reset() {
    setSelected(null);
    setForm(initialForm());
    setLookup(null);
    setMessage("");
    setError("");
    setModalError("");
  }

  function openCreateModal() {
    setSelected(null);
    setForm(initialForm());
    setLookup(null);
    setMessage("");
    setError("");
    setModalError("");
    setIsMeetingModalOpen(true);
  }

  function closeMeetingModal() {
    setIsMeetingModalOpen(false);
    setSelected(null);
    setForm(initialForm());
    setLookup(null);
    setModalError("");
  }

  function handleCommitteeChange(value) {
    const committee = findCommittee(value);
    setForm((prev) => ({
      ...prev,
      committee_id: value,
      chair_user_id: prev.chair_user_id || (committee?.chair_user_id ? String(committee.chair_user_id) : ""),
      secretary_user_id: prev.secretary_user_id || (committee?.secretary_user_id ? String(committee.secretary_user_id) : ""),
    }));
  }

  async function startMeeting(id, isQuorate) {
    if (typeof isQuorate !== "boolean") return;

    setStartLoading(true);
    setError("");
    setMessage("");
    try {
      await api.post(`/meetings/${id}/start`, { is_quorate: isQuorate });
      await load();
      if (selected?.id === id) {
        reset();
      }
      setStartModalMeeting(null);
      setMessage(
        isQuorate
          ? "Sitzung gestartet: Die Sitzung ist Beschlussfähig."
          : "Sitzung gestartet: Die Sitzung ist nicht Beschlussfähig."
      );
    } catch (err) {
      setError(err.message);
    } finally {
      setStartLoading(false);
    }
  }

  async function stopMeeting(id) {
    setError("");
    setMessage("");
    try {
      const result = await api.post(`/meetings/${id}/stop`, {});
      await load();
      if (selected?.id === id) reset();
      if (agendaModal?.meeting?.id === id) setAgendaModal(null);
      if (reportModal?.meeting_id === Number(id)) closeReportsModal();
      if (commentModal?.meeting_id === Number(id)) closeCommentsModal();
      if (followUpAgendaItem?.meeting?.id === Number(id)) setFollowUpAgendaItem(null);

      if (result?.protocol_document && result?.decision_report_document) {
        setMessage("Sitzung beendet, Protokoll und Beschlussbericht erzeugt");
      } else if (result?.protocol_document) {
        setMessage("Sitzung beendet und Protokoll erzeugt");
      } else if (result?.decision_report_document) {
        setMessage("Sitzung beendet und Beschlussbericht erzeugt");
      } else {
        setMessage("Sitzung beendet");
      }
    } catch (err) {
      setError(err.message);
    }
  }

  async function openAgendaModal(meeting) {
    setAgendaLoading(true);
    setError("");
    try {
      const data = await api.get(`/meetings/${meeting.id}/agenda-items`);
      setAgendaModal(data);
    } catch (err) {
      setError(err.message);
    } finally {
      setAgendaLoading(false);
    }
  }

  async function refreshAgendaModal(meetingId) {
    const data = await api.get(`/meetings/${meetingId}/agenda-items`);
    setAgendaModal(data);
  }

  async function openReportsModal(agendaItem) {
    if (!agendaModal?.meeting?.id || !agendaItem?.id) return;

    setReportLoading(true);
    setError("");
    try {
      const data = await api.get(`/meetings/${agendaModal.meeting.id}/agenda-items/${agendaItem.id}/reports`);
      setReportModal(data);
    } catch (err) {
      setError(err.message || "Berichte konnten nicht geladen werden.");
    } finally {
      setReportLoading(false);
    }
  }

  function closeReportsModal() {
    setReportModal(null);
    setReportLoading(false);
  }

  async function openCommentsModal(agendaItem) {
    if (!agendaModal?.meeting?.id || !agendaItem?.id) return;

    setCommentLoading(true);
    setError("");
    try {
      const data = await api.get(`/meetings/${agendaModal.meeting.id}/agenda-items/${agendaItem.id}/comments`);
      setCommentModal({ ...data, meeting: agendaModal.meeting });
    } catch (err) {
      setError(err.message || "Kommentare konnten nicht geladen werden.");
    } finally {
      setCommentLoading(false);
    }
  }

  async function refreshCommentsModal() {
    if (!commentModal?.meeting_id || !commentModal?.agenda_item?.id) return;
    const data = await api.get(`/meetings/${commentModal.meeting_id}/agenda-items/${commentModal.agenda_item.id}/comments`);
    setCommentModal((prev) => ({ ...data, meeting: prev?.meeting || agendaModal?.meeting || null }));
  }

  function closeCommentsModal() {
    setCommentModal(null);
    setCommentLoading(false);
  }

  async function createAgendaComment(payload) {
    if (!commentModal?.meeting_id || !commentModal?.agenda_item?.id) return;
    setCommentLoading(true);
    setError("");
    try {
      await api.post(`/meetings/${commentModal.meeting_id}/agenda-items/${commentModal.agenda_item.id}/comments`, payload);
      await refreshCommentsModal();
      await refreshAgendaModal(commentModal.meeting_id);
      setMessage("Kommentar zum TOP gespeichert.");
    } catch (err) {
      setError(err.message || "Kommentar konnte nicht gespeichert werden.");
    } finally {
      setCommentLoading(false);
    }
  }

  async function updateAgendaComment(row, payload) {
    if (!commentModal?.meeting_id || !commentModal?.agenda_item?.id || !row?.id) return;
    setCommentLoading(true);
    setError("");
    try {
      await api.put(`/meetings/${commentModal.meeting_id}/agenda-items/${commentModal.agenda_item.id}/comments/${row.id}`, payload);
      await refreshCommentsModal();
      await refreshAgendaModal(commentModal.meeting_id);
      setMessage("Kommentar aktualisiert.");
    } catch (err) {
      setError(err.message || "Kommentar konnte nicht aktualisiert werden.");
    } finally {
      setCommentLoading(false);
    }
  }

  async function deleteAgendaComment(row) {
    if (!commentModal?.meeting_id || !commentModal?.agenda_item?.id || !row?.id) return;
    if (!window.confirm("Kommentar löschen?")) return;
    setCommentLoading(true);
    setError("");
    try {
      await api.delete(`/meetings/${commentModal.meeting_id}/agenda-items/${commentModal.agenda_item.id}/comments/${row.id}`);
      await refreshCommentsModal();
      await refreshAgendaModal(commentModal.meeting_id);
      setMessage("Kommentar gelöscht.");
    } catch (err) {
      setError(err.message || "Kommentar konnte nicht gelöscht werden.");
    } finally {
      setCommentLoading(false);
    }
  }

  async function viewReportDocument(row) {
    setError("");
    try {
      await openBinary(`/documents/${row.id}/view`);
    } catch (err) {
      setError(err.message || "Bericht konnte nicht angezeigt werden.");
    }
  }

  async function downloadReportDocument(row) {
    setError("");
    try {
      await downloadBinary(`/documents/${row.id}/download`, row.file_name || row.title || `bericht-${row.id}`);
    } catch (err) {
      setError(err.message || "Bericht konnte nicht heruntergeladen werden.");
    }
  }

  async function printReportDocument(row) {
    setError("");
    try {
      await printBinary(`/documents/${row.id}/view`);
    } catch (err) {
      setError(err.message || "Bericht konnte nicht gedruckt werden.");
    }
  }

  function printAgendaSummary(agenda) {
    const printWindow = window.open("", "_blank", "noopener,noreferrer,width=900,height=700");
    if (!printWindow) {
      setError("Druckfenster konnte nicht geöffnet werden.");
      return;
    }

    const title = `${agenda?.agenda_number ? `TOP ${agenda.agenda_number} – ` : ""}${agenda?.title || "Bericht"}`;
    const summary = agenda?.case_summary || "Kein Berichtstext vorhanden.";

    printWindow.document.open();
    printWindow.document.write(`<!doctype html>
<html lang="de">
  <head>
    <meta charset="utf-8" />
    <title>${title}</title>
    <style>
      body { font-family: Arial, sans-serif; margin: 24px; line-height: 1.5; }
      h1 { font-size: 22px; margin-bottom: 8px; }
      .meta { color: #475569; margin-bottom: 20px; }
      .summary { white-space: pre-wrap; }
    </style>
  </head>
  <body>
    <h1>${title}</h1>
    <div class="meta">${agenda?.case_number ? `Vorgang ${agenda.case_number}` : ""}</div>
    <div class="summary">${summary.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;")}</div>
  </body>
</html>`);
    printWindow.document.close();
    printWindow.focus();
    window.setTimeout(() => printWindow.print(), 250);
  }

  async function assignExistingAgendaItem(agendaItemId) {
    if (!agendaModal?.meeting?.id || isMeetingLocked(agendaModal.meeting)) return;

    setAgendaLoading(true);
    setError("");
    setMessage("");
    try {
      await api.post(`/meetings/${agendaModal.meeting.id}/agenda-items/assign`, {
        agenda_item_id: agendaItemId,
      });
      await refreshAgendaModal(agendaModal.meeting.id);
      await load();
      setMessage("TOP zur Sitzung hinzugefügt");
    } catch (err) {
      setError(err.message);
    } finally {
      setAgendaLoading(false);
    }
  }

  async function createAndAssignAgendaItem(payload) {
    if (!agendaModal?.meeting?.id || isMeetingLocked(agendaModal.meeting)) return;

    setAgendaLoading(true);
    setError("");
    setMessage("");
    try {
      await api.post(`/meetings/${agendaModal.meeting.id}/agenda-items/create-and-assign`, payload);
      await refreshAgendaModal(agendaModal.meeting.id);
      await load();
      setMessage("Neuer TOP erzeugt und der Sitzung zugewiesen");
    } catch (err) {
      setError(err.message);
    } finally {
      setAgendaLoading(false);
    }
  }

  function openFollowUpAgendaModal(agendaItem) {
    if (!agendaModal?.meeting?.id || !agendaItem?.id) return;
    setFollowUpAgendaItem({ meeting: agendaModal.meeting, agendaItem });
    setError("");
    setMessage("");
  }

  async function createFollowUpAgendaItem(payload) {
    if (!followUpAgendaItem?.meeting?.id || !followUpAgendaItem?.agendaItem?.id) return;

    setAgendaLoading(true);
    setError("");
    setMessage("");
    try {
      await api.post(
        `/meetings/${followUpAgendaItem.meeting.id}/agenda-items/${followUpAgendaItem.agendaItem.id}/return-to-pool`,
        payload
      );
      setFollowUpAgendaItem(null);
      await refreshAgendaModal(followUpAgendaItem.meeting.id);
      await load();
      setMessage("Verknüpfter Folge-TOP wurde im TOP-Bestand angelegt.");
    } catch (err) {
      setError(err.message || "Folge-TOP konnte nicht angelegt werden.");
    } finally {
      setAgendaLoading(false);
    }
  }

  async function unassignAgendaItem(agendaItemId) {
    if (!agendaModal?.meeting?.id || isMeetingLocked(agendaModal.meeting)) return;

    setAgendaLoading(true);
    setError("");
    setMessage("");
    try {
      await api.post(`/meetings/${agendaModal.meeting.id}/agenda-items/${agendaItemId}/unassign`, {});
      await refreshAgendaModal(agendaModal.meeting.id);
      await load();
      setMessage("TOP aus Sitzung entfernt und wieder in den Bestand eingeordnet");
    } catch (err) {
      setError(err.message);
    } finally {
      setAgendaLoading(false);
    }
  }

  async function submit(e) {
    e.preventDefault();
    setModalError("");
    setMessage("");

    if (!form.meeting_date) {
      setModalError("Bitte ein Sitzungsdatum auswählen.");
      return;
    }

    const payload = {
      title: form.title.trim(),
      meeting_type: form.meeting_type,
      meeting_date: form.meeting_date,
      start_time: form.start_time || null,
      end_time: form.end_time || null,
      location: form.location.trim() || null,
      status: form.status,
      protocol_text: form.protocol_text.trim() || null,
      committee_id: form.committee_id ? Number(form.committee_id) : null,
      chair_user_id: form.chair_user_id ? Number(form.chair_user_id) : null,
      secretary_user_id: form.secretary_user_id ? Number(form.secretary_user_id) : null,
    };

    try {
      const successMessage = selected?.id ? "Sitzung gespeichert" : "Sitzung erstellt";

      if (selected?.id) {
        await api.put(`/meetings/${selected.id}`, payload);
      } else {
        await api.post("/meetings", payload);
      }

      await load({ nextPage: 1 });
      setPage(1);
      closeMeetingModal();
      setMessage(successMessage);
    } catch (err) {
      setModalError(err.message);
    }
  }

  async function removeItem(id, row) {
    if (isMeetingLocked(row)) return;

    setError("");
    setMessage("");
    try {
      await api.delete(`/meetings/${id}`);
      if (selected?.id === id) reset();
      if (agendaModal?.meeting?.id === id) setAgendaModal(null);
      await load();
      setMessage("Sitzung gelöscht");
    } catch (err) {
      setError(err.message);
    }
  }

  function pickUser(target, row) {
    setForm((prev) => ({ ...prev, [target]: String(row.id) }));
    setLookup(null);
  }

  return (
    <>
      <style>{`
        .modal-backdrop {
          position: fixed;
          inset: 0;
          background: rgba(15, 23, 42, 0.55);
          display: flex;
          align-items: center;
          justify-content: center;
          padding: 16px;
          z-index: 1000;
        }

        .modal-panel {
          width: min(900px, 100%);
          max-height: 92vh;
          overflow: auto;
          border-radius: 18px;
          background: rgba(255, 255, 255, 0.74);
          backdrop-filter: blur(18px);
          -webkit-backdrop-filter: blur(18px);
          border: 1px solid rgba(255, 255, 255, 0.24);
          box-shadow: 0 20px 60px rgba(0, 0, 0, 0.25);
          padding: 18px;
        }

        .modal-header {
          display: flex;
          align-items: flex-start;
          justify-content: space-between;
          gap: 16px;
          margin-bottom: 16px;
        }

        .modal-subtitle {
          margin: 6px 0 0;
          opacity: 0.75;
          font-size: 0.95rem;
        }

        .modal-close {
          border: 0;
          background: transparent;
          font-size: 28px;
          line-height: 1;
          cursor: pointer;
          padding: 4px 8px;
        }

        .switch-line {
          display: inline-flex;
          align-items: center;
          gap: 8px;
          font-weight: 600;
        }
      `}</style>

      <div className="page-grid">
        <SectionCard
          title="Sitzungen"
          subtitle="Beendete Sitzungen sind standardmäßig ausgeblendet. Suche unterstützt auch SQL-Wildcards wie % und findet zusätzlich Themen/TOPs."
          actions={
            <div style={{ display: "flex", gap: 12, alignItems: "center", flexWrap: "wrap" }}>
              <label style={{ display: "flex", gap: 8, alignItems: "center" }}>
                <input
                  type="checkbox"
                  checked={showEnded}
                  onChange={(e) => {
                    setShowEnded(e.target.checked);
                    setPage(1);
                  }}
                />
                <span>Beendete einblenden</span>
              </label>

              <input
                className="input search"
                placeholder="Suchen... (% als Wildcard möglich)"
                value={query}
                onChange={(e) => setQuery(e.target.value)}
              />

              <button className="btn" type="button" onClick={openCreateModal}>
                Neue Sitzung
              </button>
            </div>
          }
        >
          {error ? <div className="alert error">{error}</div> : null}
          {message ? <div className="alert success">{message}</div> : null}

          <div className="table-wrap">
            <table className="table">
              <thead>
                <tr>
                  <th>ID</th>
                  <th>Sitzung</th>
                  <th>Titel</th>
                  <th>Art</th>
                  <th>Datum</th>
                  <th>Ort</th>
                  <th>Status</th>
                  <th>Beschlussfähig</th>
                  <th>TOPs</th>
                  <th>Aktionen</th>
                </tr>
              </thead>
              <tbody>
                {rows.map((row) => {
                  const locked = isMeetingLocked(row);

                  return (
                    <tr
                      key={row.id}
                      onClick={() => {
                        if (!locked) openEditModal(row);
                      }}
                      style={{
                        cursor: locked ? "default" : "pointer",
                        opacity: row.status === "beendet" ? 0.75 : 1,
                      }}
                    >
                      <td>{row.id}</td>
                      <td>{row.meeting_number}</td>
                      <td>{row.title}</td>
                      <td>{meetingTypeOptions.find((item) => item.value === row.meeting_type)?.label || row.meeting_type}</td>
                      <td>{row.meeting_date}</td>
                      <td>{row.location}</td>
                      <td>{statusOptions.find((item) => item.value === row.status)?.label || row.status}</td>
                      <td>{formatQuorum(row.is_quorate)}</td>
                      <td>{row.agenda_item_count ?? 0}</td>
                      <td className="row-actions">
                        <button
                          className="mini-btn"
                          type="button"
                          onClick={(e) => {
                            e.stopPropagation();
                            setStartModalMeeting(row);
                          }}
                          disabled={startLoading || row.status === "gestartet" || row.status === "beendet"}
                        >
                          Starten
                        </button>

                        <button
                          className="mini-btn"
                          type="button"
                          onClick={(e) => {
                            e.stopPropagation();
                            stopMeeting(row.id);
                          }}
                          disabled={row.status !== "gestartet"}
                        >
                          Stoppen
                        </button>

                        <button
                          className="mini-btn"
                          type="button"
                          onClick={(e) => {
                            e.stopPropagation();
                            openEditModal(row);
                          }}
                          disabled={locked}
                        >
                          Bearbeiten
                        </button>

                        <button
                          className="mini-btn"
                          type="button"
                          onClick={(e) => {
                            e.stopPropagation();
                            openAgendaModal(row);
                          }}
                          disabled={agendaLoading && agendaModal?.meeting?.id === row.id}
                        >
                          TOPs
                        </button>

                        <button
                          className="mini-btn danger"
                          type="button"
                          onClick={(e) => {
                            e.stopPropagation();
                            removeItem(row.id, row);
                          }}
                          disabled={locked}
                        >
                          Löschen
                        </button>
                      </td>
                    </tr>
                  );
                })}

                {!rows.length ? (
                  <tr>
                    <td colSpan={10}>Keine Sitzungen gefunden</td>
                  </tr>
                ) : null}
              </tbody>
            </table>
          </div>

          {meta.total_pages > 1 ? (
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginTop: 14 }}>
              <div>
                Seite {meta.page} von {meta.total_pages} · {meta.total} Einträge
              </div>

              <div style={{ display: "flex", gap: 8 }}>
                <button
                  className="btn secondary"
                  type="button"
                  disabled={meta.page <= 1}
                  onClick={() => setPage((prev) => Math.max(1, prev - 1))}
                >
                  Zurück
                </button>

                <button
                  className="btn secondary"
                  type="button"
                  disabled={meta.page >= meta.total_pages}
                  onClick={() => setPage((prev) => Math.min(meta.total_pages, prev + 1))}
                >
                  Weiter
                </button>
              </div>
            </div>
          ) : null}
        </SectionCard>
      </div>

      {agendaModal ? (
        <AgendaAssignmentModal
          meeting={agendaModal.meeting}
          data={agendaModal}
          onAssignExisting={assignExistingAgendaItem}
          onCreateAndAssign={createAndAssignAgendaItem}
          onUnassign={unassignAgendaItem}
          onCreateFollowUp={openFollowUpAgendaModal}
          onOpenReports={openReportsModal}
          onOpenComments={openCommentsModal}
          onClose={() => setAgendaModal(null)}
          loading={agendaLoading}
        />
      ) : null}

      <FollowUpAgendaItemModal
        open={Boolean(followUpAgendaItem)}
        meeting={followUpAgendaItem?.meeting}
        agendaItem={followUpAgendaItem?.agendaItem}
        loading={agendaLoading}
        onClose={() => setFollowUpAgendaItem(null)}
        onSubmit={createFollowUpAgendaItem}
      />

      <AgendaReportsModal
        open={Boolean(reportModal)}
        data={reportModal}
        onClose={closeReportsModal}
        onView={viewReportDocument}
        onDownload={downloadReportDocument}
        onPrint={printReportDocument}
        onPrintSummary={printAgendaSummary}
      />

      <AgendaCommentsModal
        open={Boolean(commentModal)}
        data={commentModal}
        loading={commentLoading}
        onClose={closeCommentsModal}
        onCreate={createAgendaComment}
        onUpdate={updateAgendaComment}
        onDelete={deleteAgendaComment}
      />

      <StartMeetingModal
        meeting={startModalMeeting}
        loading={startLoading}
        onAnswer={(isQuorate) => startMeeting(startModalMeeting.id, isQuorate)}
        onClose={() => {
          if (!startLoading) setStartModalMeeting(null);
        }}
      />

      <MeetingEditorModal
        open={isMeetingModalOpen}
        selected={selected}
        form={form}
        setForm={setForm}
        committees={committees}
        committeeUsers={committeeUsers}
        handleCommitteeChange={handleCommitteeChange}
        setLookup={setLookup}
        onClose={closeMeetingModal}
        onSubmit={submit}
        error={modalError}
        lookupOpen={Boolean(lookup)}
      />

      {lookup ? (
        <div style={{ position: "fixed", inset: 0, zIndex: 1100 }}>
          <LookupModal
            title="Benutzer auswählen"
            rows={committeeUsers}
            columns={[
              { key: "id", label: "ID" },
              { key: "full_name", label: "Name" },
              { key: "email", label: "E-Mail" },
              { key: "role", label: "Rolle" },
            ]}
            onPick={(row) => pickUser(lookup, row)}
            onClose={() => setLookup(null)}
          />
        </div>
      ) : null}
    </>
  );
}
