// Solo Staff management — master-admin-only. See routes/admin-staff.ts for
// the full API contract and the is_protected / invite-email design notes.
// Reuses ModalShell/ModalError/SectionLabel/EmptyNote/MiniField/ActionButton/
// inputStyle/selectStyle from admin-assets-page.jsx (loaded earlier — see
// index.html) via plain global scope, same pattern admin-companies-page.jsx
// already relies on.

function AdminStaffPage({ onNavigate }) {
  const [state, setState] = useState({ status: "loading", admin: null, staff: [] });
  const [busyId, setBusyId] = useState(null);
  const [showAdd, setShowAdd] = useState(false);
  const [editing, setEditing] = useState(null); // staff row or null

  const load = () => {
    Promise.all([
      fetch("/api/admin/me", { credentials: "same-origin" }).then((r) => (r.ok ? r.json() : Promise.reject())),
      fetch("/api/admin/staff", { credentials: "same-origin" }).then((r) => (r.ok ? r.json() : Promise.reject())),
    ])
      .then(([me, staff]) => {
        if (!me.isSuperAdmin) { onNavigate("admin-approvals"); return; }
        setState({ status: "ready", admin: me.admin, staff: staff.staff || [] });
      })
      .catch(() => onNavigate("admin-login"));
  };
  useEffect(load, []); // eslint-disable-line react-hooks/exhaustive-deps -- mount-only

  const resendInvite = async (id) => {
    setBusyId(id);
    try {
      const res = await fetch(`/api/admin/staff/${id}/resend-invite`, { method: "POST", credentials: "same-origin" });
      if (res.ok) load();
    } finally { setBusyId(null); }
  };

  const deleteStaff = async (row) => {
    if (!window.confirm(`Delete ${row.name}'s staff account? This can't be undone.`)) return;
    setBusyId(row.id);
    try {
      const res = await fetch(`/api/admin/staff/${row.id}`, { method: "DELETE", credentials: "same-origin" });
      const data = await res.json().catch(() => ({}));
      if (!res.ok) { window.alert(data.error || "Something went wrong."); return; }
      load();
    } finally { setBusyId(null); }
  };

  const toggleSuspend = async (row) => {
    setBusyId(row.id);
    try {
      const nextStatus = row.status === "suspended" ? "active" : "suspended";
      const res = await fetch(`/api/admin/staff/${row.id}`, {
        method: "PATCH", credentials: "same-origin",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ status: nextStatus }),
      });
      const data = await res.json().catch(() => ({}));
      if (!res.ok) { window.alert(data.error || "Something went wrong."); return; }
      load();
    } finally { setBusyId(null); }
  };

  if (state.status === "loading") {
    return <section style={{ background: "#fff", minHeight: "calc(100vh - 88px)" }} />;
  }

  return (
    <AdminShell admin={state.admin} page="admin-staff" onNavigate={onNavigate}
      subtitle="Staff only · Master admins" title="Solo staff"
      actions={<ActionButton onClick={() => setShowAdd(true)} testId="staff-add-btn">+ Add staff</ActionButton>}>
      <SectionLabel>Staff accounts ({state.staff.length})</SectionLabel>
      {state.staff.length === 0 ? (
        <EmptyNote>No staff accounts yet.</EmptyNote>
      ) : (
        <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
          {state.staff.map((row) => (
            <StaffRow
              key={row.id} row={row} busy={busyId === row.id}
              onEdit={() => setEditing(row)}
              onResendInvite={() => resendInvite(row.id)}
              onToggleSuspend={() => toggleSuspend(row)}
              onDelete={() => deleteStaff(row)}
            />
          ))}
        </div>
      )}

      {showAdd && (
        <StaffFormModal
          title="Add staff account"
          onCancel={() => setShowAdd(false)}
          onSaved={() => { setShowAdd(false); load(); }}
        />
      )}
      {editing && (
        <StaffFormModal
          title={`Edit ${editing.name}`}
          existing={editing}
          onCancel={() => setEditing(null)}
          onSaved={() => { setEditing(null); load(); }}
        />
      )}
    </AdminShell>
  );
}

function StaffRow({ row, busy, onEdit, onResendInvite, onToggleSuspend, onDelete }) {
  const roleLabel = row.role === "super_admin" ? "Master admin" : "Solo staff";
  const pending = !row.password_set_at;
  return (
    <div style={{
      border: "1px solid rgba(0,0,0,0.14)", padding: "16px 18px",
      display: "flex", justifyContent: "space-between", alignItems: "center", gap: 16, flexWrap: "wrap",
    }}>
      <div>
        <div style={{ fontFamily: "var(--font-body)", fontSize: 14.5, fontWeight: 600, color: "#000" }}>
          {row.name}
          {row.is_protected === 1 && (
            <span style={{
              marginLeft: 10, fontSize: 9.5, letterSpacing: "0.14em", textTransform: "uppercase",
              color: "rgba(180,110,0,0.95)", fontWeight: 500,
            }}>Protected</span>
          )}
        </div>
        <div style={{ fontFamily: "var(--font-body)", fontSize: 12.5, color: "rgba(0,0,0,0.55)", marginTop: 2 }}>
          {row.email} · {roleLabel} · {row.status === "suspended" ? "Suspended" : "Active"}
          {pending ? " · Invitation pending" : ""}
        </div>
      </div>
      <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
        {pending && (
          <ActionButton disabled={busy} onClick={onResendInvite}>Resend invite</ActionButton>
        )}
        <ActionButton disabled={busy} onClick={onEdit}>Edit</ActionButton>
        {row.is_protected !== 1 && (
          <React.Fragment>
            <ActionButton disabled={busy} onClick={onToggleSuspend}>
              {row.status === "suspended" ? "Reactivate" : "Suspend"}
            </ActionButton>
            <ActionButton danger disabled={busy} onClick={onDelete}>Delete</ActionButton>
          </React.Fragment>
        )}
      </div>
    </div>
  );
}

function StaffFormModal({ title, existing, onCancel, onSaved }) {
  const [name, setName] = useState(existing ? existing.name : "");
  const [email, setEmail] = useState(existing ? existing.email : "");
  const [role, setRole] = useState(existing ? existing.role : "admin");
  const [password, setPassword] = useState("");
  const [status, setStatus] = useState("idle");
  const [error, setError] = useState("");

  const isProtected = existing && existing.is_protected === 1;

  const handleSubmit = async (e) => {
    e.preventDefault();
    setStatus("submitting");
    setError("");
    try {
      let res;
      if (existing) {
        const body = { name, email, role };
        if (password) body.password = password;
        res = await fetch(`/api/admin/staff/${existing.id}`, {
          method: "PATCH", credentials: "same-origin",
          headers: { "Content-Type": "application/json" }, body: JSON.stringify(body),
        });
      } else {
        res = await fetch("/api/admin/staff", {
          method: "POST", credentials: "same-origin",
          headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name, email, role }),
        });
      }
      const data = await res.json().catch(() => ({}));
      if (!res.ok) { setError(data.error || "Something went wrong."); setStatus("idle"); return; }
      onSaved();
    } catch {
      setError("Couldn't reach the server. Check your connection and try again.");
      setStatus("idle");
    }
  };

  return (
    <ModalShell title={title} onCancel={onCancel}>
      {error && <ModalError>{error}</ModalError>}
      <form onSubmit={handleSubmit}>
        <MiniField label="Name">
          <input style={inputStyle} value={name} onChange={(e) => setName(e.target.value)} required />
        </MiniField>
        <MiniField label="Email">
          <input style={inputStyle} type="email" value={email} onChange={(e) => setEmail(e.target.value)} required />
        </MiniField>
        <MiniField label="Role">
          <select
            style={selectStyle} value={role} onChange={(e) => setRole(e.target.value)}
            disabled={isProtected}
          >
            <option value="admin">Solo staff (read-only everywhere)</option>
            <option value="super_admin">Master admin (full access)</option>
          </select>
        </MiniField>
        {existing && (
          <MiniField label="Set a new password (optional)">
            <input
              style={inputStyle} type="password" autoComplete="new-password"
              value={password} onChange={(e) => setPassword(e.target.value)}
              placeholder="Leave blank to keep their current password"
            />
          </MiniField>
        )}
        {!existing && (
          <div style={{ fontFamily: "var(--font-body)", fontSize: 12.5, color: "rgba(0,0,0,0.55)", margin: "-6px 0 18px" }}>
            They'll be emailed a link to set their own password.
          </div>
        )}
        <div style={{ display: "flex", justifyContent: "flex-end", gap: 10, marginTop: 10 }}>
          <ActionButton disabled={status === "submitting"} danger onClick={onCancel}>Cancel</ActionButton>
          <button type="submit" disabled={status === "submitting"} style={{
            background: "#000", color: "#fff", border: "1px solid #000",
            padding: "10px 18px", cursor: "pointer",
            fontFamily: "var(--font-body)", fontSize: 11.5, fontWeight: 500,
            letterSpacing: "0.14em", textTransform: "uppercase",
          }}>
            {status === "submitting" ? "Saving…" : existing ? "Save changes" : "Add staff"}
          </button>
        </div>
      </form>
    </ModalShell>
  );
}

// Reached via the "set your password" link in a new staff member's invite
// email — see routes/admin-staff.ts's sendInviteEmail and app.jsx's
// resetType="admin-invite" handling. Mirrors AdminResetPasswordPage
// (admin-portal-page.jsx) but posts to /api/admin/accept-invite and uses
// "Set your password" framing instead of "Reset your password", since a
// brand new account never had a password to reset.
function AdminAcceptInvitePage({ onNavigate, token }) {
  const [password, setPassword] = useState("");
  const [confirmPassword, setConfirmPassword] = useState("");
  const [showPassword, setShowPassword] = useState(false);
  const [status, setStatus] = useState("idle"); // idle → submitting → done
  const [error, setError] = useState("");

  const canSubmit = token && password.length >= 10 && password === confirmPassword && status !== "submitting";

  const handleSubmit = async (e) => {
    e.preventDefault();
    if (!canSubmit) return;
    setStatus("submitting");
    setError("");
    try {
      const res = await fetch("/api/admin/accept-invite", {
        method: "POST", credentials: "same-origin",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ token, password }),
      });
      const data = await res.json().catch(() => ({}));
      if (!res.ok) { setError(data.error || "Something went wrong. Please try again."); setStatus("idle"); return; }
      setStatus("done");
    } catch {
      setError("Couldn't reach the server. Check your connection and try again.");
      setStatus("idle");
    }
  };

  return (
    <section style={{
      background: "#fff", color: "#000", minHeight: "calc(100vh - 88px)",
      padding: "80px 36px 120px", display: "flex", alignItems: "center", justifyContent: "center",
      position: "relative",
    }}>
      <CornerHairlines />
      <div style={{ width: "100%", maxWidth: 440, position: "relative", zIndex: 2 }}>
        <div style={{
          display: "flex", alignItems: "center", gap: 10,
          fontFamily: "var(--font-body)", fontSize: 10,
          letterSpacing: "0.32em", textTransform: "uppercase",
          color: "rgba(180,110,0,0.95)", fontWeight: 500, marginBottom: 32,
        }}>
          <LiveDot />
          <span>Staff only · internal system</span>
        </div>

        <h1 style={{
          fontFamily: "var(--font-display)", fontWeight: 700,
          fontSize: "clamp(32px, 5vw, 48px)", lineHeight: 1,
          letterSpacing: "-0.005em", textTransform: "uppercase",
          margin: "0 0 18px", color: "#000",
        }}>
          Set your password.
        </h1>

        {!token ? (
          <div style={{ background: "rgba(0,0,0,0.03)", border: "1px solid rgba(0,0,0,0.16)", padding: "32px" }}>
            <p style={{ fontFamily: "var(--font-body)", fontSize: 14.5, lineHeight: 1.6, color: "rgba(0,0,0,0.7)", margin: "0 0 24px" }}>
              This page is only reachable via the link in a staff invite email.
            </p>
            <button type="button" onClick={() => onNavigate("admin-login")} style={{
              background: "#000", color: "#fff", border: "1px solid #000",
              padding: "16px 22px", cursor: "pointer",
              fontFamily: "var(--font-body)", fontSize: 13, fontWeight: 500,
              letterSpacing: "0.22em", textTransform: "uppercase",
            }}>Sign in →</button>
          </div>
        ) : status === "done" ? (
          <div style={{ background: "rgba(0,0,0,0.03)", border: "1px solid rgba(0,0,0,0.16)", padding: "32px" }}>
            <p style={{ fontFamily: "var(--font-body)", fontSize: 15, lineHeight: 1.6, color: "rgba(0,0,0,0.85)", margin: "0 0 24px" }}>
              Your password has been set. You can now sign in.
            </p>
            <button type="button" onClick={() => onNavigate("admin-login")} style={{
              background: "#000", color: "#fff", border: "1px solid #000",
              padding: "16px 22px", cursor: "pointer",
              fontFamily: "var(--font-body)", fontSize: 13, fontWeight: 500,
              letterSpacing: "0.22em", textTransform: "uppercase",
            }}>Sign in →</button>
          </div>
        ) : (
          <form onSubmit={handleSubmit} style={{
            background: "rgba(0,0,0,0.03)", border: "1px solid rgba(0,0,0,0.16)",
            backdropFilter: "blur(6px)", padding: "32px",
          }}>
            {error && (
              <div style={{
                background: "rgba(190,40,40,0.08)", border: "1px solid rgba(190,40,40,0.35)",
                color: "#8a1f1f", padding: "14px 16px", marginBottom: 22,
                fontFamily: "var(--font-body)", fontSize: 13.5, lineHeight: 1.5,
              }}>{error}</div>
            )}
            <FieldBlock label="Password" right={
              <button type="button" onClick={() => setShowPassword((v) => !v)} style={{
                background: "none", border: "none", cursor: "pointer", padding: 0,
                fontFamily: "var(--font-body)", fontSize: 10,
                letterSpacing: "0.22em", textTransform: "uppercase",
                color: "rgba(0,0,0,0.6)", fontWeight: 500,
              }}>{showPassword ? "Hide" : "Show"}</button>
            } hint="At least 10 characters.">
              <DarkInput
                type={showPassword ? "text" : "password"} autoComplete="new-password" required
                value={password} onChange={(e) => setPassword(e.target.value)}
              />
            </FieldBlock>
            <FieldBlock label="Confirm password">
              <DarkInput
                type={showPassword ? "text" : "password"} autoComplete="new-password" required
                value={confirmPassword} onChange={(e) => setConfirmPassword(e.target.value)}
              />
            </FieldBlock>
            {password && confirmPassword && password !== confirmPassword && (
              <div style={{ fontFamily: "var(--font-body)", fontSize: 12.5, color: "#8a1f1f", margin: "-10px 0 22px" }}>
                Passwords don't match.
              </div>
            )}
            <button type="submit" disabled={!canSubmit} style={{
              width: "100%", marginTop: 12,
              background: canSubmit ? "#000" : "rgba(0,0,0,0.15)",
              color: canSubmit ? "#fff" : "rgba(0,0,0,0.5)",
              border: `1px solid ${canSubmit ? "#000" : "rgba(0,0,0,0.15)"}`,
              padding: "18px 22px", cursor: canSubmit ? "pointer" : "not-allowed",
              fontFamily: "var(--font-body)", fontSize: 13, fontWeight: 500,
              letterSpacing: "0.22em", textTransform: "uppercase",
              transition: "background 140ms, color 140ms",
            }}>
              {status === "submitting" ? "Setting…" : "Set password →"}
            </button>
          </form>
        )}
      </div>
    </section>
  );
}
