// OPT-GATE-01 · Gate dashboard

// Swipe-to-reveal row: the truck item is dragged left to reveal a "Confirm
// gate-out" button behind it. The button only exists after a swipe — it is not
// shown by default. Tapping the row (when closed) still opens the movement log.
const SwipeGateOutRow = ({ amber, onOpen, onConfirm, children }) => {
  const Ic = window.Icons;
  const W = 156;                    // revealed action width
  const dragging = React.useRef(false);
  const startX = React.useRef(0);
  const moved = React.useRef(false);
  const [tx, setTx] = useState(0);  // foreground translateX (0 … -W)

  const begin = (e) => { dragging.current = true; moved.current = false; startX.current = e.clientX - tx; try { e.currentTarget.setPointerCapture(e.pointerId); } catch (_) {} };
  const move = (e) => {
    if (!dragging.current) return;
    let x = e.clientX - startX.current;
    x = Math.max(-W, Math.min(0, x));
    if (Math.abs(x - tx) > 3) moved.current = true;
    setTx(x);
  };
  const end = () => { if (!dragging.current) return; dragging.current = false; setTx(tx < -W * 0.4 ? -W : 0); };
  const onRowClick = () => { if (moved.current) { moved.current = false; return; } if (tx < 0) { setTx(0); return; } onOpen(); };

  return (
    <div style={{ position: "relative", overflow: "hidden" }}>
      {/* Revealed action, sitting behind the row */}
      <button onClick={onConfirm} aria-label="Confirm gate-out"
        style={{ position: "absolute", top: 0, right: 0, bottom: 0, width: W, border: "none", cursor: "pointer", background: "var(--success)", color: "#fff", display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: 4, fontFamily: "inherit", fontSize: 12.5, fontWeight: 700 }}>
        <Ic.CheckCircle size={20}/> Confirm gate-out
      </button>
      {/* Foreground row — opaque, slides left on swipe */}
      <div onPointerDown={begin} onPointerMove={move} onPointerUp={end} onPointerCancel={end} onClick={onRowClick}
        className={`op-row ${amber ? "amber" : ""}`}
        style={{ position: "relative", transform: `translateX(${tx}px)`, transition: dragging.current ? "none" : "transform .22s", background: "var(--card)", cursor: "pointer", touchAction: "pan-y" }}>
        {children}
        {tx === 0 && <Ic.ChevronLeft size={16} style={{ color: "var(--muted-foreground)", flexShrink: 0, marginLeft: 2 }}/>}
      </div>
    </div>
  );
};

const DashboardScreen = ({ t, go }) => {
  const { Btn, Pill, Kpi, Banner, Toast } = window.Op;
  const Ic = window.Icons, FD = window.OD;
  const state = t.dashboard; // default | quiet | noExpected | loading | offline
  const [exited, setExited] = useState(() => new Set());
  const [toast, setToast] = useState("");
  const confirmExit = (s) => { setExited(prev => { const n = new Set(prev); n.add(s.id); return n; }); setToast(`Gate-out confirmed · ${s.plate}`); setTimeout(() => setToast(""), 2200); };

  const expected = state === "noExpected" ? [] : FD.EXPECTED;
  const onsite = (state === "quiet" ? [] : FD.ONSITE).filter(s => !exited.has(s.id));
  const loading = state === "loading";

  const ExpRow = (e) => {
    const [tone, label] = FD.STATUS_PILL[e.status];
    return (
      <button className="op-row" key={e.id} onClick={() => go("manualEntry")}>
        <span className={`op-row-thumb ${e.dir === "out" ? "soil" : e.product.includes("Fuerte") ? "pulp" : ""}`}>
          {e.dir === "out" ? <Ic.Truck size={19}/> : <Ic.Leaf size={19}/>}
        </span>
        <div className="op-row-body">
          <div className="op-row-title">{e.who}</div>
          <div className="op-row-sub">{e.product} · {FD.KG(e.qty)}</div>
        </div>
        <div className="op-row-meta">
          <div style={{ fontSize: 12.5, fontWeight: 600, fontVariantNumeric: "tabular-nums" }}>{e.eta}</div>
          <div style={{ marginTop: 4 }}><Pill tone={tone}>{label}</Pill></div>
        </div>
      </button>
    );
  };

  const SiteRow = (s) => {
    const d = FD.dwell(s.elapsedMin);
    const ready = s.stage === "Warehouse" || s.stage === "Loading bay"; // process complete → can gate-out
    const info = (
      <>
        <span className={`op-row-thumb ${s.dir === "out" ? "soil" : ""}`}><Ic.Truck size={19}/></span>
        <div className="op-row-body">
          <div className="op-row-title">{s.plate} · <span className="op-muted" style={{ fontWeight: 500 }}>{s.who}</span></div>
          <div className="op-row-sub"><span className="op-gpn">{s.gpn.replace("GPN-20260516-", "GPN-…")}</span> · {s.stage}</div>
        </div>
        <div className="op-row-meta">
          <span className={`op-dwell ${d.tone}`}><Ic.Clock size={13}/> {d.txt}</span>
          <div className="op-muted" style={{ fontSize: 11.5, marginTop: 3 }}>{ready ? <span style={{ color: "var(--success)", fontWeight: 600 }}>Ready to exit</span> : `in ${s.entered}`}</div>
        </div>
      </>
    );
    if (!ready) {
      return (
        <button className={`op-row ${d.tone === "red" || d.tone === "amber" ? "amber" : ""}`} key={s.id} onClick={() => go("movementLog")}>{info}</button>
      );
    }
    return (
      <SwipeGateOutRow key={s.id} amber={d.tone === "red" || d.tone === "amber"} onOpen={() => go("movementLog")} onConfirm={() => confirmExit(s)}>
        {info}
      </SwipeGateOutRow>
    );
  };

  const longDwellCount = FD.ONSITE.filter(s => s.elapsedMin >= 240).length;

  return (
    <div className="op-body">
      <div className="op-pad">
        {/* Hero CTA strip */}
        <div style={{ display: "flex", gap: 12, marginBottom: 18 }}>
          <Btn variant="primary" size="hero" icon={Ic.QR} style={{ flex: 1 }} onClick={() => go("scan")}>Scan gate pass</Btn>
          <Btn variant="outline" size="hero" icon={Ic.Edit} style={{ flexBasis: 240 }} onClick={() => go("manualEntry")}>Manual entry</Btn>
          <button className="op-chip" style={{ height: 72, padding: "0 18px", borderRadius: "var(--radius-xl)" }}>
            <Ic.Calendar size={18}/>
            <div style={{ textAlign: "left", lineHeight: 1.2 }}>
              <div style={{ fontSize: 11, color: "var(--muted-foreground)", fontWeight: 600 }}>VIEWING</div>
              <div style={{ fontSize: 14, fontWeight: 600 }}>Today · {FD.TODAY}</div>
            </div>
            <Ic.ChevronDown size={16} style={{ color: "var(--muted-foreground)" }}/>
          </button>
        </div>

        {state === "longDwell" || longDwellCount > 0 ? (
          <div style={{ marginBottom: 16 }}>
            <Banner tone="warning" icon={Ic.Clock} title={`${longDwellCount} trucks on site over 4 hours`}
              desc="Review the highlighted rows — long dwell may indicate a bottleneck at QC, warehouse, or loading."/>
          </div>
        ) : null}

        {/* Working area */}
        <div style={{ display: "grid", gridTemplateColumns: "1.25fr 1.1fr 0.95fr", gap: 16, alignItems: "start" }}>
          {/* Expected today */}
          <div className="op-card flush">
            <div className="op-card-head"><div><div className="op-card-title">Expected today</div><div className="op-card-sub">{expected.length} scheduled · sorted by ETA</div></div></div>
            <div className="op-list" style={{ maxHeight: 340, overflowY: "auto" }}>
              {loading
                ? Array.from({ length: 5 }).map((_, i) => <div key={i} style={{ padding: "14px 16px", borderBottom: "1px solid var(--border)" }}><div className="op-skel" style={{ height: 14, width: "60%" }}/><div className="op-skel" style={{ height: 11, width: "40%", marginTop: 8 }}/></div>)
                : expected.length ? expected.map(ExpRow)
                : <div className="op-empty" style={{ padding: "40px 24px" }}><div className="op-empty-art" style={{ width: 72, height: 72, borderRadius: 20 }}><Ic.Calendar size={30}/></div><div className="op-empty-title" style={{ fontSize: 17 }}>No scheduled arrivals</div><div className="op-empty-desc" style={{ fontSize: 13 }}>Use Manual entry for unexpected walk-ins.</div></div>}
            </div>
          </div>

          {/* Currently on site */}
          <div className="op-card flush">
            <div className="op-card-head">
              <div><div className="op-card-title">Currently on site</div><div className="op-card-sub">{onsite.length} trucks inside</div></div>
              <span className="op-sec-link" onClick={() => go("activeTrucks")}>View all</span>
            </div>
            <div className="op-list" style={{ maxHeight: 340, overflowY: "auto" }}>
              {loading
                ? Array.from({ length: 4 }).map((_, i) => <div key={i} style={{ padding: "14px 16px", borderBottom: "1px solid var(--border)" }}><div className="op-skel" style={{ height: 14, width: "55%" }}/><div className="op-skel" style={{ height: 11, width: "45%", marginTop: 8 }}/></div>)
                : onsite.length ? onsite.map(SiteRow)
                : <div className="op-empty" style={{ padding: "40px 24px" }}><div className="op-empty-art" style={{ width: 72, height: 72, borderRadius: 20 }}><Ic.Truck size={30}/></div><div className="op-empty-title" style={{ fontSize: 17 }}>No trucks on site</div><div className="op-empty-desc" style={{ fontSize: 13 }}>Scan a gate pass to admit the first arrival.</div></div>}
            </div>
          </div>

          {/* Stats */}
          <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
            <div className="op-grid-2" style={{ gap: 12 }}>
              <Kpi label="Arrivals" icon={Ic.ArrowDown} value={loading ? "—" : FD.STATS.arrivals}/>
              <Kpi label="Exits" icon={Ic.ArrowUp} value={loading ? "—" : FD.STATS.exits}/>
              <Kpi label="Avg dwell" icon={Ic.Clock} value={loading ? "—" : `${FD.STATS.dwellH}h`} unit={`${FD.STATS.dwellM}m`}/>
              <Kpi label="Mismatches" icon={Ic.Warning} value={loading ? "—" : FD.STATS.mismatches} warn onClick={() => go("exceptions")}/>
            </div>
            {/* Mini gate-events timeline */}
            <div className="op-card flush">
              <div className="op-card-head" style={{ paddingBottom: 8 }}><div className="op-card-title" style={{ fontSize: 13.5 }}>Recent gate events</div></div>
              <div style={{ padding: "0 16px 14px" }}>
                {[
                  ["09:14", "Entry", "KDG 104T · Esther Njeri", ""],
                  ["09:02", "Exit", "KDA 332B · completed", "muted"],
                  ["08:55", "Override", "Late arrival · supervisor PIN", "warning"],
                  ["08:34", "Gross weight", "KCB 412G · 16,420 kg", ""],
                ].map(([time, type, sub, tone], i) => (
                  <div key={i} style={{ display: "flex", gap: 11, padding: "8px 0", alignItems: "flex-start" }}>
                    <span style={{ fontSize: 11.5, color: "var(--muted-foreground)", width: 38, flexShrink: 0, fontVariantNumeric: "tabular-nums", paddingTop: 1 }}>{time}</span>
                    <span className={`op-tl-dot ${tone}`} style={{ width: 24, height: 24 }}>
                      {type === "Exit" ? <Ic.ArrowUp size={13}/> : type === "Override" ? <Ic.Warning size={13}/> : type === "Gross weight" ? <Ic.Gauge size={13}/> : <Ic.Truck size={13}/>}
                    </span>
                    <div style={{ minWidth: 0, flex: 1 }}>
                      <div style={{ fontSize: 12.5, fontWeight: 600 }}>{type}</div>
                      <div className="op-muted" style={{ fontSize: 11.5 }}>{sub}</div>
                    </div>
                  </div>
                ))}
              </div>
            </div>
          </div>
        </div>
      </div>
      <Toast show={!!toast}>{toast}</Toast>
    </div>
  );
};

window.OptPages = Object.assign(window.OptPages || {}, {
  dashboard: { chrome: "tabs", tab: "Gate", render: (ctx) => <DashboardScreen {...ctx}/> },
});
