// Public · Operator floor (#/floor)
// ---------------------------------------------------------------------------
// Where floor staff clock in with their own username + PIN, separate from Joy's
// admin passcode. Once signed in they get the live Shop floor board (reused from
// the studio) scoped to their permissions, and every Start/Finish is attributed
// to them. Backend: /api/staff/login | /me | /logout (already built).
// Joy, signed in as admin, is treated as a floor superuser here too.
// ---------------------------------------------------------------------------

function FloorApp() {
  const app = useApp();
  const [me, setMe] = useState(null); // null = checking; else { signedIn, ... }

  const refresh = async () => {
    try { setMe(await api.staffMe()); }
    catch (e) { setMe({ signedIn: false }); }
  };
  useEffect(() => { refresh(); }, []);

  const signOut = async () => { try { await api.staffLogout(); } catch (e) {} setMe({ signedIn: false }); };

  // The floor needs the live studio database.
  if (app && app.mode && app.mode !== "api") {
    return (
      <main className="page section">
        <div style={{ maxWidth: 460, margin: "0 auto" }} className="stitched stitched-sage">
          <div style={{ padding: 28, textAlign: "center", color: "var(--ink-2)" }}>
            <div className="script" style={{ fontSize: 34, color: "var(--rose-deep)" }}>Floor sign-in</div>
            <p style={{ marginTop: 10 }}>The shop floor runs on the live studio database, so it's available on the deployed site — not in this preview.</p>
          </div>
        </div>
      </main>
    );
  }

  if (me === null) {
    return <main className="page section"><div style={{ maxWidth: 460, margin: "0 auto", textAlign: "center", color: "var(--ink-3)", padding: 40 }}>Checking…</div></main>;
  }

  if (!me.signedIn) return <OperatorLogin onSignedIn={refresh} />;

  const canFloor = me.isAdmin || (me.effective && me.effective.canViewFloor);
  return (
    <main className="page section">
      <div style={{ maxWidth: 1120, margin: "0 auto" }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 18, flexWrap: "wrap", gap: 10 }}>
          <div>
            <div className="script" style={{ fontSize: 32, color: "var(--rose-deep)", lineHeight: 1 }}>Hello, {me.name}</div>
            <div className="smallcaps" style={{ color: "var(--sage-deep)" }}>{me.isAdmin ? "Owner" : me.role} · floor sign-in</div>
          </div>
          <button className="btn btn-ghost btn-small" onClick={signOut}>Sign out</button>
        </div>

        {canFloor
          ? (typeof ShopFloorTab !== "undefined"
              ? <>
                  <MyClockBar />
                  <MyWeek />
                  <ShopFloorTab />
                </>
              : <div className="stitched" style={{ padding: 24, textAlign: "center", color: "var(--ink-3)" }}>The floor board didn't load — refresh the page.</div>)
          : (
            <div className="stitched" style={{ padding: 24, textAlign: "center", color: "var(--ink-2)" }}>
              Your account doesn't have floor access yet. Ask Joy to switch on “See the floor board” for you under Floor team.
            </div>
          )}
      </div>
    </main>
  );
}

function OperatorLogin({ onSignedIn }) {
  const [username, setUsername] = useState("");
  const [pin, setPin] = useState("");
  const [busy, setBusy] = useState(false);
  const [err, setErr] = useState("");

  const submit = async () => {
    if (!username || !pin) { setErr("Enter your username and PIN."); return; }
    setBusy(true); setErr("");
    try { await api.staffLogin(username.trim(), pin); onSignedIn(); }
    catch (e) { setErr(e && e.message ? e.message : "Sign-in failed."); setBusy(false); }
  };
  const onKey = (e) => { if (e.key === "Enter") submit(); };

  return (
    <main className="page section">
      <div style={{ maxWidth: 420, margin: "0 auto" }}>
        <div style={{ textAlign: "center", marginBottom: 18 }}>
          <div className="script" style={{ fontSize: 42, color: "var(--rose-deep)", lineHeight: 1 }}>Floor sign-in</div>
          <div className="smallcaps" style={{ color: "var(--ink-2)" }}>Hazelbelle Embroidery &amp; Print</div>
        </div>
        <div className="stitched" style={{ padding: 24 }}>
          <p style={{ marginTop: 0, color: "var(--ink-2)", fontSize: 15 }}>Sign in with the username and PIN Joy set up for you. Your start/stop times are recorded under your name.</p>
          <div className="field">
            <label>Username</label>
            <input value={username} autoCapitalize="none" autoComplete="username" onChange={e => setUsername(e.target.value)} onKeyDown={onKey} placeholder="firstname" />
          </div>
          <div className="field">
            <label>PIN</label>
            <input type="password" inputMode="numeric" autoComplete="current-password" value={pin} onChange={e => setPin(e.target.value)} onKeyDown={onKey} placeholder="••••" />
          </div>
          {err && <div style={{ color: "var(--rose-deep)", fontSize: 14, margin: "4px 0 10px" }}>{err}</div>}
          <button className="btn" style={{ width: "100%" }} disabled={busy} onClick={submit}>{busy ? "Signing in…" : "Sign in"}</button>
          <div style={{ textAlign: "center", marginTop: 14, fontSize: 13 }}>
            <a href="#/">← Back to the site</a>
          </div>
        </div>
      </div>
    </main>
  );
}

Object.assign(window, { FloorApp, OperatorLogin });

// [HB] Ported from white-label: worker self-service clock + weekly schedule + time-off.
// [HB-WL] The operator's own clock — clock in/out and take lunch/breaks from
// their floor screen. Time here feeds the admin Timecard & labor report.
function MyClockBar() {
  const app = useApp();
  const [st, setSt] = useState(null);
  const [busy, setBusy] = useState(false);
  const [, setTick] = useState(0);

  const load = async () => { try { setSt(await api.myShift()); } catch (e) { setSt(null); } };
  useEffect(() => {
    load();
    const poll = setInterval(load, 30000);
    const clock = setInterval(() => setTick(t => t + 1), 1000);
    return () => { clearInterval(poll); clearInterval(clock); };
  }, []);

  if (!st || st.noStaffSession) return null;

  const act = async (fn) => {
    setBusy(true);
    try { setSt(await fn()); }
    catch (e) { app.toast?.(e.message || "Couldn't update the clock."); }
    finally { setBusy(false); }
  };

  const mins = (since) => Math.max(0, Math.round((Date.now() - since) / 60000));
  const hhmm = (m) => (m >= 60 ? `${Math.floor(m / 60)}h ${m % 60}m` : `${m}m`);

  return (
    <div className="stitched" style={{ padding: 14, marginBottom: 16, borderColor: st.onBreak ? "var(--gold)" : st.onClock ? "var(--sage)" : "var(--line)" }}>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12, flexWrap: "wrap" }}>
        <div>
          <div className="smallcaps" style={{ color: "var(--ink-3)", fontSize: 11 }}>My clock</div>
          <div style={{ fontSize: 17, marginTop: 2 }}>
            {!st.onClock
              ? <span style={{ color: "var(--ink-3)" }}>Not clocked in</span>
              : st.onBreak
                ? <span style={{ color: "var(--gold-deep)" }}>On {st.breakKind} · {hhmm(mins(st.breakSince))}</span>
                : <span style={{ color: "var(--sage-deep)" }}>Clocked in · {hhmm(mins(st.since))}</span>}
          </div>
          <div style={{ color: "var(--ink-3)", fontSize: 12, marginTop: 2 }}>
            Today: {hhmm(st.paidMinutes)} paid{st.breakMinutes > 0 ? ` · ${hhmm(st.breakMinutes)} on breaks` : ""}
          </div>
        </div>
        <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
          {!st.onClock ? (
            <button className="btn btn-small" disabled={busy} onClick={() => act(() => api.myClock("in"))}>Clock in</button>
          ) : st.onBreak ? (
            <button className="btn btn-small" disabled={busy} onClick={() => act(() => api.myBreak(st.breakKind))}>End {st.breakKind}</button>
          ) : (
            <>
              <button className="btn btn-ghost btn-small" disabled={busy} onClick={() => act(() => api.myBreak("break"))}>Take a break</button>
              <button className="btn btn-ghost btn-small" disabled={busy} onClick={() => act(() => api.myBreak("lunch"))}>Lunch</button>
              <button className="btn btn-small" disabled={busy} onClick={() => act(() => api.myClock("out"))}>Clock out</button>
            </>
          )}
        </div>
      </div>
      {st.onBreak && (
        <div style={{ color: "var(--ink-3)", fontSize: 12, marginTop: 8 }}>
          Your job timer is paused while you're on {st.breakKind}. Break time isn't counted as paid hours.
        </div>
      )}

      {/* Today's record — exactly what the studio sees. */}
      {(st.events || []).length > 0 && (
        <div style={{ marginTop: 10, borderTop: "1px dashed var(--line)", paddingTop: 8 }}>
          <div className="smallcaps" style={{ color: "var(--ink-3)", fontSize: 11, marginBottom: 4 }}>Today's record</div>
          <div style={{ display: "flex", flexWrap: "wrap", gap: 10 }}>
            {st.events.map((e, i) => {
              const LABEL = {
                "in": "Clocked in", "out": "Clocked out",
                "break-start": "Break started", "break-end": "Break ended",
                "lunch-start": "Lunch started", "lunch-end": "Lunch ended",
              };
              const tone = e.type === "in" ? "var(--sage-deep)"
                : e.type === "out" ? "var(--ink-2)"
                : "var(--gold-deep)";
              return (
                <span key={i} style={{ fontSize: 12, color: tone }}>
                  {LABEL[e.type] || e.type}{" "}
                  <span className="mono">{new Date(e.at).toLocaleTimeString([], { hour: "numeric", minute: "2-digit" })}</span>
                  {e.manual ? <span style={{ color: "var(--ink-3)" }}> (adjusted)</span> : null}
                </span>
              );
            })}
          </div>
        </div>
      )}
    </div>
  );
}

// [HB-WL] The operator's own week: when they're rostered, plus raising and
// tracking time-off / overtime requests.
function MyWeek() {
  const app = useApp();
  const [me, setMe] = useState(null);
  const [data, setData] = useState(null);
  const [requests, setRequests] = useState([]);
  const [form, setForm] = useState(null);
  const [busy, setBusy] = useState(false);
  const [showAll, setShowAll] = useState(false);

  const monday = (() => {
    const d = new Date();
    d.setDate(d.getDate() - ((d.getDay() + 6) % 7));
    d.setHours(12, 0, 0, 0);
    return d;
  })();
  const ymd = (d) => { const p = (n) => String(n).padStart(2, "0"); return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}`; };
  const addDays = (base, n) => { const d = new Date(base); d.setDate(d.getDate() + n); return d; };
  const start = ymd(monday), end = ymd(addDays(monday, 6));
  const DAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];

  const load = async () => {
    try {
      const [who, sched, reqs] = await Promise.all([
        api.staffMe(),
        api.getSchedule(start, end),
        api.listRequests().catch(() => []),
      ]);
      setMe(who);
      setData(sched);
      setRequests(reqs || []);
    } catch (e) { setData({ shifts: [], timeOff: [] }); }
  };
  useEffect(() => { load(); }, []);

  if (!data || !me) return null;

  const myId = me.id;
  const mine = (data.shifts || []).filter(s => s.staffId === myId);
  const myOff = (data.timeOff || []).filter(o => o.staffId === myId);
  const weekHours = mine.reduce((s, x) => s + x.hours, 0);

  const submit = async () => {
    setBusy(true);
    try {
      await api.addRequest(form);
      app.toast?.("Request sent to the studio.");
      setForm(null);
      await load();
    } catch (e) { app.toast?.(e.message || "Couldn't send that."); }
    finally { setBusy(false); }
  };
  const withdraw = async (r) => {
    if (!window.confirm("Withdraw this request?")) return;
    try { await api.deleteRequest(r.id); await load(); }
    catch (e) { app.toast?.(e.message || "Couldn't withdraw."); }
  };

  const KIND_LABEL = { time_off: "Time off", overtime: "Overtime", other: "Other" };
  const TONE = { pending: "var(--gold-deep)", approved: "var(--sage-deep)", denied: "var(--rose-deep)" };
  const visible = showAll ? requests : requests.slice(0, 4);

  return (
    <div className="stitched" style={{ padding: 14, marginBottom: 16 }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", flexWrap: "wrap", gap: 8 }}>
        <div>
          <div className="smallcaps" style={{ color: "var(--ink-3)", fontSize: 11 }}>My week</div>
          <div style={{ fontSize: 15, marginTop: 2 }}>
            {weekHours > 0 ? <>You're scheduled for <strong>{weekHours}h</strong> this week</> : <span style={{ color: "var(--ink-3)" }}>Nothing scheduled this week</span>}
          </div>
        </div>
        <button className="btn btn-ghost btn-small" onClick={() => setForm({ kind: "time_off", startDate: ymd(new Date()), endDate: ymd(new Date()), hours: "", reason: "" })}>
          Request time off / overtime
        </button>
      </div>

      {/* The week at a glance */}
      <div style={{ display: "grid", gridTemplateColumns: "repeat(7, 1fr)", gap: 4, marginTop: 10 }}>
        {DAYS.map((d, i) => {
          const date = ymd(addDays(monday, i));
          const sh = mine.find(s => s.date === date);
          const off = myOff.find(o => date >= o.startDate && date <= o.endDate);
          const isToday = date === ymd(new Date());
          return (
            <div key={d} style={{ textAlign: "center" }}>
              <div style={{ fontSize: 11, color: isToday ? "var(--sage-deep)" : "var(--ink-3)", fontWeight: isToday ? 700 : 400 }}>{d}</div>
              <div style={{
                marginTop: 3, borderRadius: 6, padding: "6px 2px", fontSize: 11, lineHeight: 1.35,
                background: off ? "var(--line)" : sh ? "var(--sage)" : "transparent",
                color: off ? "var(--ink-3)" : sh ? "#fff" : "var(--ink-3)",
                border: (!off && !sh) ? "1px dashed var(--line)" : "none",
                minHeight: 34,
              }}>
                {off ? "Off" : sh ? (<>{sh.startTime}<br />{sh.endTime}{sh.machineName ? <div style={{ fontSize: 10, opacity: .85 }}>{sh.machineName}</div> : null}</>) : "—"}
              </div>
            </div>
          );
        })}
      </div>

      {/* Request form */}
      {form && (
        <div className="stitched stitched-sage" style={{ padding: 12, marginTop: 12 }}>
          <div className="field-row">
            <div className="field">
              <label>Type</label>
              <select value={form.kind} onChange={e => setForm({ ...form, kind: e.target.value })}>
                <option value="time_off">Time off</option>
                <option value="overtime">Overtime</option>
                <option value="other">Other</option>
              </select>
            </div>
            <div className="field"><label>From</label><input type="date" value={form.startDate} onChange={e => setForm({ ...form, startDate: e.target.value, endDate: form.endDate < e.target.value ? e.target.value : form.endDate })} /></div>
            <div className="field"><label>To</label><input type="date" value={form.endDate} min={form.startDate} onChange={e => setForm({ ...form, endDate: e.target.value })} /></div>
            {form.kind !== "time_off" && (
              <div className="field"><label>Hours</label><input value={form.hours} onChange={e => setForm({ ...form, hours: e.target.value })} placeholder="e.g. 4" inputMode="decimal" /></div>
            )}
          </div>
          <div className="field"><label>Reason (optional)</label><input value={form.reason} onChange={e => setForm({ ...form, reason: e.target.value })} placeholder="Family appointment, covering a rush order…" /></div>
          <div style={{ display: "flex", gap: 8 }}>
            <button className="btn btn-small" onClick={submit} disabled={busy}>{busy ? "Sending…" : "Send request"}</button>
            <button className="btn btn-ghost btn-small" onClick={() => setForm(null)}>Cancel</button>
          </div>
        </div>
      )}

      {/* My requests */}
      {requests.length > 0 && (
        <div style={{ marginTop: 12, borderTop: "1px dashed var(--line)", paddingTop: 8 }}>
          <div className="smallcaps" style={{ color: "var(--ink-3)", fontSize: 11, marginBottom: 4 }}>My requests</div>
          {visible.map(r => (
            <div key={r.id} style={{ display: "flex", justifyContent: "space-between", gap: 8, flexWrap: "wrap", fontSize: 13, padding: "3px 0" }}>
              <div>
                {KIND_LABEL[r.kind] || r.kind} · {r.startDate}{r.endDate !== r.startDate ? ` → ${r.endDate}` : ""}
                {r.hours ? ` · ${r.hours}h` : ""}
                {r.decisionNote ? <span style={{ color: "var(--ink-3)" }}> · {r.decisionNote}</span> : null}
              </div>
              <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
                <span style={{ color: TONE[r.status] }}>{r.status}</span>
                {r.status === "pending" && <button className="btn btn-ghost btn-small" style={{ padding: "0 6px", fontSize: 11 }} onClick={() => withdraw(r)}>withdraw</button>}
              </div>
            </div>
          ))}
          {requests.length > 4 && (
            <button className="btn btn-ghost btn-small" style={{ marginTop: 4, fontSize: 11 }} onClick={() => setShowAll(v => !v)}>
              {showAll ? "Show fewer" : `Show all ${requests.length}`}
            </button>
          )}
        </div>
      )}
    </div>
  );
}

Object.assign(window, { MyClockBar, MyWeek });
