// hydor-page-attendance.jsx — fingerprint-style attendance & visit logging.
// Live selfie (getUserMedia, no uploads) + automatic GPS + server-stamped time.
// Visible to everyone EXCEPT the owner; managers/co-founder see the whole team's log.

const ATT_TYPES = [
  { key: "checkin", label: "Check in", ar: "تسجيل حضور", cls: "in", color: "var(--pos)",
    icon: "M15 3h4a2 2 0 012 2v14a2 2 0 01-2 2h-4M10 17l5-5-5-5M15 12H3" },
  { key: "checkout", label: "Check out", ar: "تسجيل انصراف", cls: "out", color: "var(--warn)",
    icon: "M9 21H5a2 2 0 01-2-2V5a2 2 0 012-2h4M16 17l5-5-5-5M21 12H9" },
  { key: "visit_start", label: "Visit start", ar: "بدء زيارة", cls: "vs", color: "var(--accent)",
    icon: "M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z" },
  { key: "visit_end", label: "Visit end", ar: "إنهاء زيارة", cls: "ve", color: "var(--accent-3)",
    icon: "M20 6L9 17l-5-5" },
];
const ATT_BY = {}; ATT_TYPES.forEach((t) => (ATT_BY[t.key] = t));

function fmtAttTime(ts) {
  const d = new Date(ts);
  return d.toLocaleString("en-GB", { day: "2-digit", month: "short", hour: "2-digit", minute: "2-digit" });
}

function AttendancePage() {
  const s = useHydor();
  const push = useToast();
  const role = useRole();
  const me = Hydor.currentUser();
  const seeAll = Hydor.can(role, "seeAllAttendance");
  const isVisit = (k) => k === "visit_start" || k === "visit_end";

  const [tab, setTab] = React.useState("checkin");
  const [step, setStep] = React.useState("home");   // home | camera | review
  const [type, setType] = React.useState("checkin");
  const [partyId, setPartyId] = React.useState("");
  const [facing, setFacing] = React.useState("user");
  const [actualFacing, setActualFacing] = React.useState("user");
  const [camReady, setCamReady] = React.useState(false);
  const [camError, setCamError] = React.useState("");
  const [geo, setGeo] = React.useState(null);
  const [photo, setPhoto] = React.useState("");
  const [clock, setClock] = React.useState(new Date());
  const videoRef = React.useRef(null);
  const streamRef = React.useRef(null);
  const canvasRef = React.useRef(null);
  const flashRef = React.useRef(null);

  const tdef = ATT_BY[type];

  // live clock
  React.useEffect(() => { const t = setInterval(() => setClock(new Date()), 1000); return () => clearInterval(t); }, []);
  // geolocation (auto, refreshed when opening the tool)
  const locate = React.useCallback(() => {
    if (!navigator.geolocation) return;
    navigator.geolocation.getCurrentPosition(
      (p) => setGeo({ lat: p.coords.latitude, lon: p.coords.longitude, acc: p.coords.accuracy }),
      () => {}, { enableHighAccuracy: true, timeout: 9000 });
  }, []);
  React.useEffect(() => { locate(); }, [locate]);

  // camera stream lifecycle
  function stopStream() { if (streamRef.current) { streamRef.current.getTracks().forEach((t) => t.stop()); streamRef.current = null; } }
  React.useEffect(() => {
    let active = true;
    async function start() {
      stopStream();
      setCamReady(false); setCamError("");
      if (step !== "camera") return;
      // Robust camera selection: prefer the requested facing (rear for visit-end) but never hard-fail.
      // 1) try an explicit back/front device by label, 2) fall back to facingMode ideal, 3) any camera.
      async function pickStream() {
        const wantRear = facing === "environment";
        try {
          const devs = (await navigator.mediaDevices.enumerateDevices()).filter((d) => d.kind === "videoinput");
          if (devs.length > 1) {
            const rx = wantRear ? /back|rear|environment|world/i : /front|user|face|self/i;
            const match = devs.find((d) => rx.test(d.label || ""));
            if (match) {
              try { return await navigator.mediaDevices.getUserMedia({ video: { deviceId: { exact: match.deviceId } }, audio: false }); } catch (e) {}
            }
          }
        } catch (e) {}
        // facingMode ideal — picks rear on phones/tablets, gracefully uses the only camera on laptops
        try { return await navigator.mediaDevices.getUserMedia({ video: { facingMode: { ideal: facing } }, audio: false }); } catch (e) {}
        // last resort: any camera
        return await navigator.mediaDevices.getUserMedia({ video: true, audio: false });
      }
      try {
        const st = await pickStream();
        if (!active) { st.getTracks().forEach((t) => t.stop()); return; }
        streamRef.current = st;
        // detect what we actually got, so the mirror + label reflect reality (laptop rear request → front cam)
        try {
          const settings = st.getVideoTracks()[0] && st.getVideoTracks()[0].getSettings ? st.getVideoTracks()[0].getSettings() : {};
          const fm = settings.facingMode;
          if (fm === "user" || fm === "environment") setActualFacing(fm);
          else setActualFacing(facing); // unknown (most laptops) — trust requested, but it's typically the front cam
        } catch (e) { setActualFacing(facing); }
        if (videoRef.current) {
          videoRef.current.srcObject = st;
          videoRef.current.onloadedmetadata = () => { if (active) setCamReady(true); };
          videoRef.current.play().then(() => { if (active) setCamReady(true); }).catch(() => {});
        }
      } catch (e) { if (active) setCamError(e && e.name === "NotAllowedError" ? "Camera permission was blocked. Allow camera access in your browser, then reopen." : "No camera available on this device."); }
    }
    start();
    return () => { active = false; };
  }, [step, facing]);
  React.useEffect(() => () => stopStream(), []);

  const myToday = React.useMemo(() => {
    const today = new Date().toISOString().slice(0, 10);
    return s.attendance.filter((a) => me && a.userId === me.id && (a.ts || "").slice(0, 10) === today);
  }, [s.attendance, me]);
  const lastEntry = myToday[0];

  function openCamera(k) {
    setType(k);
    if (!isVisit(k)) setPartyId("");
    // visit end → installed-device photo, default to the REAR camera
    setFacing(k === "visit_end" ? "environment" : "user");
    locate();
    setStep("camera");
  }

  function capture() {
    const v = videoRef.current;
    const fl = flashRef.current;
    if (fl) { fl.style.transition = "none"; fl.style.opacity = ".9"; requestAnimationFrame(() => { fl.style.transition = "opacity .5s"; fl.style.opacity = "0"; }); }
    let url = "";
    if (v && v.videoWidth) {
      const maxW = 460, scale = Math.min(1, maxW / v.videoWidth);
      const w = Math.round(v.videoWidth * scale), h = Math.round(v.videoHeight * scale);
      const c = canvasRef.current; c.width = w; c.height = h;
      const ctx = c.getContext("2d");
      if (actualFacing === "user") { ctx.translate(w, 0); ctx.scale(-1, 1); }
      ctx.drawImage(v, 0, 0, w, h);
      ctx.setTransform(1, 0, 0, 1, 0, 0);
      const bar = Math.round(h * 0.13);
      ctx.fillStyle = "rgba(0,0,0,.5)"; ctx.fillRect(0, h - bar, w, bar);
      ctx.fillStyle = "#fff"; ctx.textBaseline = "middle";
      ctx.font = "600 " + Math.round(bar * 0.32) + 'px "IBM Plex Mono", monospace';
      const hm = clock.toLocaleTimeString("en-GB", { hour: "2-digit", minute: "2-digit" });
      ctx.fillText(hm + "  ·  " + tdef.label, Math.round(w * 0.04), h - bar * 0.62);
      ctx.fillStyle = "#bcd4f5"; ctx.font = "400 " + Math.round(bar * 0.24) + 'px "IBM Plex Sans", sans-serif';
      const coords = geo ? geo.lat.toFixed(4) + ", " + geo.lon.toFixed(4) : "location pending";
      ctx.fillText("HYDOR · " + coords, Math.round(w * 0.04), h - bar * 0.24);
      url = c.toDataURL("image/jpeg", 0.55);
    }
    setPhoto(url);
    stopStream();
    setStep("review");
  }

  function confirm() {
    Hydor.logAttendance({
      type, photo,
      lat: geo ? geo.lat : null, lon: geo ? geo.lon : null, accuracy: geo ? geo.acc : null,
      partyId: isVisit(type) ? partyId : "",
      note: type === "visit_end" ? "Photo of installed device" : "",
    });
    const past = { checkin: "Checked in", checkout: "Checked out", visit_start: "Visit started", visit_end: "Visit ended" }[type];
    push(past + " · " + clock.toLocaleTimeString("en-GB", { hour: "2-digit", minute: "2-digit" }));
    setPhoto(""); setStep("home"); setTab("mine");
  }

  function cancelCapture() { stopStream(); setPhoto(""); setStep("home"); }

  // visible customers (employees only see their own added clients)
  const myCustomers = s.parties.filter((p) => p.type === "customer" && (Hydor.can(role, "seeAllContacts") || !p.createdBy || (me && p.createdBy === me.id)));
  const partyName = (id) => { const p = s.parties.find((x) => x.id === id); return p ? p.name : ""; };
  const userName = (id) => { const u = s.users.find((x) => x.id === id); return u ? u.name : "—"; };

  const hh = String(clock.getHours()).padStart(2, "0"), mm = String(clock.getMinutes()).padStart(2, "0"), ss = String(clock.getSeconds()).padStart(2, "0");
  const coordsTxt = geo ? geo.lat.toFixed(4) + ", " + geo.lon.toFixed(4) : "Locating…";

  return (
    <div className="att-wrap">
      <div className="att-tabs">
        <button className={"tab" + (tab === "checkin" ? " on" : "")} onClick={() => setTab("checkin")}>Check in / out</button>
        <button className={"tab" + (tab === "mine" ? " on" : "")} onClick={() => setTab("mine")}>My log</button>
        {seeAll && <button className={"tab" + (tab === "team" ? " on" : "")} onClick={() => setTab("team")}>Team log</button>}
      </div>

      {tab === "checkin" && (
        <div className="att-checkin-grid">
          {/* left: clock + status + type picker */}
          <div className="att-card hx-panel-pad">
            <div className="att-clockhead">
              <div>
                <div className="hx-eyebrow">Now</div>
                <div className="att-clock" style={{ marginTop: 8 }}>{hh}:{mm}:<span className="ms">{ss}</span></div>
                <div className="hx-sub" style={{ marginTop: 8 }}>{clock.toLocaleDateString("en-GB", { weekday: "long", day: "2-digit", month: "long", year: "numeric" })}</div>
              </div>
              <div className="att-geo"><span className="pulse"></span>
                <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z" /><circle cx="12" cy="10" r="3" /></svg>
                <span className="hx-num" style={{ color: "var(--text)" }}>{coordsTxt}</span>
              </div>
            </div>

            {lastEntry && (
              <div style={{ display: "flex", alignItems: "center", gap: 11, padding: "11px 14px", borderRadius: 12, background: "var(--bg-2)", border: "1px solid var(--border)", marginBottom: 18 }}>
                <span style={{ width: 9, height: 9, borderRadius: "50%", background: ATT_BY[lastEntry.type].color, flex: "none" }}></span>
                <span style={{ fontSize: 13, color: "var(--text-2)" }}>Last today: <b style={{ color: "var(--text)" }}>{ATT_BY[lastEntry.type].label}</b> at <span className="hx-num">{new Date(lastEntry.ts).toLocaleTimeString("en-GB", { hour: "2-digit", minute: "2-digit" })}</span></span>
              </div>
            )}

            <div className="hx-eyebrow" style={{ marginBottom: 10 }}>Choose what to log</div>
            <div className="att-types">
              {ATT_TYPES.map((t) => (
                <div key={t.key} className={"att-type " + t.cls + (type === t.key ? " on" : "")} onClick={() => { setType(t.key); if (!isVisit(t.key)) setPartyId(""); }}>
                  <span className="ti"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d={t.icon} /></svg></span>
                  <span><span className="tl">{t.label}</span><span className="ta">{t.ar}</span></span>
                </div>
              ))}
            </div>

            {isVisit(type) && (
              <div style={{ marginTop: 16 }}>
                <label style={{ fontSize: 12, fontWeight: 600, color: "var(--text-3)", display: "block", marginBottom: 6 }}>Customer being visited <span style={{ fontWeight: 400 }}>(optional)</span></label>
                <select className="sel" value={partyId} onChange={(e) => setPartyId(e.target.value)}>
                  <option value="">— not specified —</option>
                  {myCustomers.map((c) => <option key={c.id} value={c.id}>{c.name}</option>)}
                </select>
              </div>
            )}
          </div>

          {/* right: droplet trigger */}
          <div className="att-card hx-panel-pad" style={{ display: "flex", flexDirection: "column", alignItems: "center", paddingTop: 26, paddingBottom: 26 }}>
            <div className="att-droplabel">{tdef.label}</div>
            <div className="att-drop" onClick={() => openCamera(type)} role="button" title="Open camera">
              <div className="att-dropfill" style={{ background: tdef.cls === "in" ? "linear-gradient(160deg,#49e0ad,#34d3a0 50%,#22b487)" : tdef.cls === "out" ? "linear-gradient(160deg,#ffd277,#ffc24b 50%,#e0a02f)" : "linear-gradient(160deg,#4f9bff,#3b8cff 45%,#2f6fe0)" }}></div>
              <div className="att-dropspec"></div>
              <div className="att-dropcta">
                <svg width="30" height="30" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7"><path d="M23 19a2 2 0 01-2 2H3a2 2 0 01-2-2V8a2 2 0 012-2h4l2-3h6l2 3h4a2 2 0 012 2z" /><circle cx="12" cy="13" r="4" /></svg>
                <span className="lbl">Tap to open camera</span>
              </div>
            </div>
            <p className="hx-sub" style={{ textAlign: "center", marginTop: 20, maxWidth: 250 }}>
              Frame your pose in front of the building or the attendance board, then capture. <b style={{ color: "var(--text-2)" }}>Live photo only — no uploads.</b>
            </p>
          </div>
        </div>
      )}

      {tab === "mine" && <AttendanceLog rows={s.attendance.filter((a) => me && a.userId === me.id)} partyName={partyName} userName={userName} showUser={false} canDelete={false} push={push} />}
      {tab === "team" && seeAll && <AttendanceLog rows={s.attendance} partyName={partyName} userName={userName} showUser={true} canDelete={true} push={push} users={s.users} />}

      {/* ===== fullscreen camera ===== */}
      {step === "camera" && (
        <div className="att-overlay">
          <video ref={videoRef} className={"att-feed" + (actualFacing === "user" ? " mirror" : "")} autoPlay playsInline muted></video>
          {(!camReady || camError) && <div className="att-feedph">{camError || "Starting camera…"}</div>}
          <div className="att-camtop">
            <div className="att-x" onClick={cancelCapture}><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2"><path d="M18 6L6 18M6 6l12 12" /></svg></div>
            <div className="att-badge" style={{ background: tdef.color, color: tdef.cls === "out" ? "#1a1303" : "#04130d" }}>{tdef.label}{isVisit(type) && partyId ? " · " + partyName(partyId) : ""}</div>
            <div className="att-camtime">{hh}:{mm}</div>
          </div>
          <div className="att-fg"><i></i><i></i><i></i><i></i></div>
          <div className="att-guidetxt">{type === "visit_end"
            ? (actualFacing === "user" ? "Take a picture of the installed device. No rear camera detected — using the available camera; flip if needed." : "Take a picture of the installed device (rear camera).")
            : "Stand in front of the building or the attendance board, then tap to capture."}</div>
          <div className="att-cambottom">
            <div className="hx-num" style={{ color: "#cfe0f7", fontSize: 11, width: 60, display: "flex", alignItems: "center", gap: 5 }}>
              <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z" /><circle cx="12" cy="10" r="3" /></svg>
              {geo ? "±" + Math.round(geo.acc) + "m" : "…"}
            </div>
            <div className="att-shutter" onClick={camReady ? capture : undefined} style={{ opacity: camReady ? 1 : 0.4, pointerEvents: camReady ? "auto" : "none" }}><div className="core"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M23 19a2 2 0 01-2 2H3a2 2 0 01-2-2V8a2 2 0 012-2h4l2-3h6l2 3h4a2 2 0 012 2z" /><circle cx="12" cy="13" r="4" /></svg></div></div>
            <div className="att-flip" onClick={() => setFacing((f) => (f === "user" ? "environment" : "user"))} title="Flip camera"><svg width="21" height="21" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M23 4v6h-6M1 20v-6h6" /><path d="M3.5 9a9 9 0 0114.9-3.4L23 10M1 14l4.6 4.4A9 9 0 0020.5 15" /></svg></div>
          </div>
          <div className="att-flash" ref={flashRef}></div>
        </div>
      )}

      {/* ===== review ===== */}
      {step === "review" && (
        <div className="att-overlay">
          {photo ? <img className="att-revimg" src={photo} alt="attendance capture" /> : <div className="att-feedph" style={{ position: "absolute", inset: 0 }}>Photo preview unavailable on this device — it will be captured live on a phone.</div>}
          <div className="att-revshade"></div>
          <div className="att-camtop" style={{ background: "linear-gradient(180deg,rgba(0,0,0,.6),transparent)" }}>
            <div className="att-badge" style={{ background: tdef.color, color: tdef.cls === "out" ? "#1a1303" : "#04130d" }}>{tdef.label}</div>
          </div>
          <div className="att-revbottom">
            <div style={{ display: "flex", flexDirection: "column", gap: 7, marginBottom: 16 }}>
              <div style={{ display: "flex", alignItems: "center", gap: 9, fontSize: 12.5, color: "#e9eef7" }}>
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="var(--accent-2)" strokeWidth="2"><circle cx="12" cy="12" r="9" /><path d="M12 7v5l3 2" /></svg>
                <b className="hx-num">{hh}:{mm}:{ss}</b> · captured live
              </div>
              <div style={{ display: "flex", alignItems: "center", gap: 9, fontSize: 12.5, color: "#e9eef7" }}>
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="var(--accent-2)" strokeWidth="2"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z" /><circle cx="12" cy="10" r="3" /></svg>
                <b className="hx-num">{coordsTxt}</b>{geo ? " · ±" + Math.round(geo.acc) + "m" : ""}
              </div>
              {isVisit(type) && partyId && (
                <div style={{ display: "flex", alignItems: "center", gap: 9, fontSize: 12.5, color: "#e9eef7" }}>
                  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="var(--accent-2)" strokeWidth="2"><path d="M20 7H4M20 12H4M20 17H4" /></svg>{partyName(partyId)}
                </div>
              )}
            </div>
            <div className="att-revactions">
              <Btn variant="ghost" icon="refresh" onClick={() => { setPhoto(""); setStep("camera"); }} style={{ flex: 1, justifyContent: "center", background: "rgba(255,255,255,.12)", color: "#fff", borderColor: "#ffffff33" }}>Retake</Btn>
              <Btn variant="primary" icon="check" onClick={confirm} style={{ flex: 1, justifyContent: "center" }}>Confirm &amp; log</Btn>
            </div>
          </div>
        </div>
      )}

      <canvas ref={canvasRef} style={{ display: "none" }}></canvas>
    </div>
  );
}

function AttendanceLog({ rows, partyName, userName, showUser, canDelete, push, users }) {
  const [emp, setEmp] = React.useState("");
  const [kind, setKind] = React.useState("all");
  let list = rows.slice().sort((a, b) => (a.ts < b.ts ? 1 : -1));
  if (emp) list = list.filter((r) => r.userId === emp);
  if (kind !== "all") list = list.filter((r) => r.type === kind);

  return (
    <div className="att-card" style={{ overflow: "hidden" }}>
      <div className="toolbar" style={{ padding: "14px 18px", borderBottom: "1px solid var(--border)", margin: 0 }}>
        {showUser && users && (
          <select className="sel" style={{ width: 180 }} value={emp} onChange={(e) => setEmp(e.target.value)}>
            <option value="">All employees</option>
            {users.filter((u) => u.active).map((u) => <option key={u.id} value={u.id}>{u.name}</option>)}
          </select>
        )}
        <select className="sel" style={{ width: 150 }} value={kind} onChange={(e) => setKind(e.target.value)}>
          <option value="all">All types</option>
          {ATT_TYPES.map((t) => <option key={t.key} value={t.key}>{t.label}</option>)}
        </select>
        <div className="grow" style={{ flex: 1 }} />
        <span className="hx-sub">{list.length} {list.length === 1 ? "entry" : "entries"}</span>
      </div>

      {list.length === 0 ? (
        <Empty icon="clock" title="No attendance yet">Check-ins, check-outs and customer visits will appear here with their photo, time and location.</Empty>
      ) : (
        <table className="hx-table">
          <thead><tr>
            <th>Photo</th>{showUser && <th>Employee</th>}<th>Type</th><th>When</th><th>Location</th><th>Customer</th>{canDelete && <th></th>}
          </tr></thead>
          <tbody>
            {list.map((r) => {
              const t = ATT_BY[r.type] || ATT_TYPES[0];
              const maps = r.lat != null ? "https://www.google.com/maps?q=" + r.lat + "," + r.lon : null;
              return (
                <tr key={r.id}>
                  <td>{r.photo ? <img className="att-log-thumb" src={r.photo} alt="" /> : <span className="att-log-thumb" style={{ display: "grid", placeItems: "center", color: "var(--text-3)" }}><Icon name="camera" size={16} /></span>}</td>
                  {showUser && <td style={{ fontWeight: 500 }}>{userName(r.userId)}{r.employeeCode && <span className="hx-code" style={{ marginLeft: 7 }}>{r.employeeCode}</span>}</td>}
                  <td><Badge color={t.cls === "in" ? "green" : t.cls === "out" ? "amber" : "blue"} dot>{t.label}</Badge></td>
                  <td className="num" style={{ color: "var(--text-2)", whiteSpace: "nowrap" }}>{fmtAttTime(r.ts)}</td>
                  <td className="num" style={{ fontSize: 12 }}>
                    {r.lat != null ? <a href={maps} target="_blank" rel="noopener" style={{ color: "var(--accent-2)" }}>{r.lat.toFixed(4)}, {r.lon.toFixed(4)}{r.accuracy != null ? " · ±" + r.accuracy + "m" : ""}</a> : <span style={{ color: "var(--text-3)" }}>—</span>}
                  </td>
                  <td style={{ color: "var(--text-2)", fontSize: 12.5 }}>{r.partyId ? partyName(r.partyId) : <span style={{ color: "var(--text-3)" }}>—</span>}</td>
                  {canDelete && <td className="r"><Btn variant="ghost" sm icon="trash" onClick={() => { Hydor.deleteAttendance(r.id); push("Entry removed."); }} /></td>}
                </tr>
              );
            })}
          </tbody>
        </table>
      )}
    </div>
  );
}

Object.assign(window, { AttendancePage });
