// ───────────────────────────────────────────────────────────────
// Busco Ops — Overview (Hub) + Operations (Daily Log) screens · v2
// Tighter, denser, no emoji. Top-nav layout.
// ───────────────────────────────────────────────────────────────

const {
  AreaChart, Area, BarChart, Bar, LineChart, Line, PieChart, Pie, Cell,
  XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend, ReferenceLine
} = Recharts;

const tickStyle = { fontSize: 10.5, fill: "var(--muted-2)", fontFamily: "IBM Plex Mono" };
const tipStyle = {
  borderRadius: 6, border: "1px solid var(--border)",
  fontSize: 11.5, fontFamily: "IBM Plex Sans",
  boxShadow: "0 8px 24px rgba(11,23,32,.10)",
  padding: "6px 10px"
};

// Build the Offloaded-vs-Delivered chart series for a given range from the
// live entries. 7D/30D = daily, 90D = weekly buckets, MAX = monthly.
const _isoLocal = (d) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
const _dm = (d) => `${d.getDate()}/${d.getMonth() + 1}`;
const _dayShort = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
function buscoChartSeries(range, entries) {
  const today = new Date(); today.setHours(0, 0, 0, 0);

  if (range === "MAX") {
    if (!entries.length) return [{ d: "—", off: 0, del: 0 }];
    const earliest = entries.reduce((min, e) => (e.date < min ? e.date : min), entries[0].date);
    const start = new Date(earliest.slice(0, 4), Number(earliest.slice(5, 7)) - 1, 1);
    const months = [];
    for (let d = new Date(start); d <= today; d.setMonth(d.getMonth() + 1)) months.push(new Date(d));
    const map = {};
    months.forEach((m) => { map[_isoLocal(m).slice(0, 7)] = { d: m.toLocaleString("en-US", { month: "short" }) + " '" + String(m.getFullYear()).slice(2), off: 0, del: 0 }; });
    for (const e of entries) { const k = String(e.date).slice(0, 7); if (map[k]) { map[k].off += e.offloaded; map[k].del += e.delivered; } }
    return months.map((m) => map[_isoLocal(m).slice(0, 7)]);
  }

  if (range === "90D") {
    const arr = [];
    for (let i = 12; i >= 0; i--) {
      const end = new Date(today); end.setDate(end.getDate() - i * 7);
      const start = new Date(end); start.setDate(start.getDate() - 6);
      arr.push({ start, end, off: 0, del: 0, d: _dm(start) });
    }
    for (const e of entries) {
      const ed = new Date(e.date.slice(0, 4), Number(e.date.slice(5, 7)) - 1, Number(e.date.slice(8, 10)));
      for (const w of arr) { if (ed >= w.start && ed <= w.end) { w.off += e.offloaded; w.del += e.delivered; break; } }
    }
    return arr.map((w) => ({ d: w.d, off: w.off, del: w.del }));
  }

  const days = range === "30D" ? 30 : 7;
  const arr = []; const map = {};
  for (let i = days - 1; i >= 0; i--) {
    const d = new Date(today); d.setDate(d.getDate() - i);
    const o = { d: days <= 7 ? _dayShort[d.getDay()] : _dm(d), off: 0, del: 0 };
    map[_isoLocal(d)] = o; arr.push(o);
  }
  for (const e of entries) { const k = String(e.date).slice(0, 10); if (map[k]) { map[k].off += e.offloaded; map[k].del += e.delivered; } }
  return arr;
}

// ── OVERVIEW (Hub) ────────────────────────────────────────────
function HubScreen({ onToast }) {
  const [range, setRangeState] = useState(() => buscoPref.get("busco-hub-range", "7D"));
  const setRange = (r) => { setRangeState(r); buscoPref.set("busco-hub-range", r); };
  const [reportPhase, setReportPhase] = useState("Morning");
  const todayRate = rate(TODAY_DELIVERED, TODAY_OFFLOADED);
  const flagged = CLIENT_ROWS.filter((c) => c.offloaded > 0 && c.rate < 75);
  const todayISO = new Date().toISOString().slice(0, 10);
  const yesterdayISO = (() => { const d = new Date(); d.setDate(d.getDate() - 1); return d.toISOString().slice(0, 10); })();
  const totalToday = ENTRIES.filter((e) => e.date === todayISO).length;
  // Returns only count once the evening delivered number is in — a morning-only
  // entry is pending, not returned.
  const todayReturned = ENTRIES.filter((e) => e.date === todayISO && e.delivered > 0).reduce((a, e) => a + (e.returned || 0), 0);

  // Incomplete-days tracker: past entries where offloaded was logged but the
  // evening delivered count was never added (delivered still 0). Today is
  // excluded — those legitimately aren't in yet.
  const incomplete = ENTRIES.filter((e) => e.date < todayISO && e.offloaded > 0 && e.delivered === 0);
  const incompleteDays = [...new Set(incomplete.map((e) => e.date))].sort().reverse();

  // Yesterday's runs — delivery numbers are only known the next day, so the
  // overview reconciles against *yesterday* rather than today.
  // Yesterday's MANUAL log only — courier reports (source 'upload') are excluded
  // so the overview reflects what Busco logged, not the clients' per-courier files.
  const yesterdayRuns = ENTRIES.filter((e) => e.date === yesterdayISO && e.source !== "upload");
  const cityAgg = {};
  for (const e of yesterdayRuns) {
    if (!cityAgg[e.city]) cityAgg[e.city] = { city: e.city, off: 0, del: 0, ret: 0, couriers: 0 };
    const a = cityAgg[e.city];
    a.off += e.offloaded; a.del += e.delivered;
    a.ret += e.delivered > 0 ? Math.max(0, e.offloaded - e.delivered) : 0;
    a.couriers += e.courierCount || 0;
  }
  const yesterdayCities = Object.values(cityAgg).sort((a, b) => b.off - a.off);

  const chartData = buscoChartSeries(range, ENTRIES);
  const rangeLabel = { "7D": "Last 7 days", "30D": "Last 30 days", "90D": "Last 90 days", "MAX": "All time" }[range];

  // ── Daily report (the WhatsApp morning/evening report, on the overview) ──
  // Morning = what each client offloaded today; Evening = what came back delivered.
  const isMorningReport = reportPhase === "Morning";
  const todayEntries = ENTRIES.filter((e) => e.date === todayISO);
  const reportByClient = {};
  for (const e of todayEntries) {
    if (!reportByClient[e.client]) reportByClient[e.client] = { client: e.client, offloaded: 0, delivered: 0, couriers: new Set(), courierCount: 0, runs: 0 };
    const m = reportByClient[e.client];
    m.offloaded += e.offloaded; m.delivered += e.delivered; m.runs += 1;
    if (e.courier && e.courier !== "—") m.couriers.add(e.courier);
    if (e.courierCount) m.courierCount += e.courierCount;
  }
  const reportRows = Object.values(reportByClient)
    .map((m) => ({ ...m, couriers: m.courierCount || m.couriers.size || m.runs }))
    .sort((a, b) => (isMorningReport ? b.offloaded - a.offloaded : b.delivered - a.delivered));
  const reportTotal = reportRows.reduce((a, m) => a + (isMorningReport ? m.offloaded : m.delivered), 0);

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 18 }}>
      {flagged.length > 0 &&
      <div className="banner warn">
          <Icon name="alert" size={16} color="var(--warn-700)" />
          <div>
            <b>{flagged.length} {window.t(flagged.length === 1 ? "client below the 75% target." : "clients below the 75% target.")}</b>{" "}
            <span style={{ color: "var(--muted)" }}>
              {flagged.map((c) => c.name).join(" · ")} — {window.t("review courier assignments.")}
            </span>
          </div>
          <button className="btn sm" style={{ marginLeft: "auto" }} onClick={() => opsNav("clients")}>
            {window.t("View clients")} <Icon name="arrow-right" size={11} />
          </button>
        </div>
      }

      {incomplete.length > 0 &&
        <div className="banner" style={{ background: "var(--warn-50)", borderColor: "var(--warn-100)", color: "var(--warn-700)" }}>
          <Icon name="alert-circle" size={16} color="var(--warn-700)" />
          <div>
            <b>{incomplete.length} {incomplete.length === 1 ? window.t("entry is missing its delivered count.") : window.t("entries are missing their delivered count.")}</b>{" "}
            <span style={{ color: "var(--muted)" }}>
              {window.t("Offloaded was logged but the evening delivered number was never added")}
              {incompleteDays.length > 0 && <> · {incompleteDays.slice(0, 3).map((d) => fmtDate(d)).join(", ")}{incompleteDays.length > 3 ? "…" : ""}</>}
            </span>
          </div>
          <button className="btn sm" style={{ marginLeft: "auto" }} onClick={() => { opsNav("log"); setTimeout(() => window.dispatchEvent(new CustomEvent("busco:flag-incomplete")), 150); }}>
            {window.t("Complete in daily log")} <Icon name="arrow-right" size={11} />
          </button>
        </div>
      }

      <div className="kpi-row" data-tour="kpis">
        <KPI label={t("Offloaded today")} value={fmtNum(TODAY_OFFLOADED)} sub={t("across all clients")} icon="package" tint="var(--b50)" accent="var(--b600)" />
        <KPI label={t("Delivered today")} value={fmtNum(TODAY_DELIVERED)} sub={t("parcels completed")} icon="check-circle" tint="var(--good-50)" accent="var(--good-700)" />
        <KPI label={t("Today's rate")} value={`${todayRate}%`} sub={todayRate >= 75 ? t("above 75% target") : t("below 75% target")}
        icon={todayRate >= 75 ? "trend" : "trend-down"} tint={todayRate >= 75 ? "var(--good-50)" : "var(--crit-50)"}
        accent={todayRate >= 75 ? "var(--good-700)" : "var(--crit-700)"} tone={todayRate >= 75 ? "good" : "bad"} />
        <KPI label={t("Returned today")} value={fmtNum(todayReturned)} sub={t("across all clients")} icon="trend-down" tint="var(--warn-50)" accent="var(--warn-700)" />
      </div>

      {/* Daily report — the morning/evening report Busco reads each day, on the overview */}
      <div className="card" data-tour="report" style={{ border: "1px solid var(--b300)", boxShadow: "0 0 0 3px var(--b50), var(--sh-2, 0 4px 14px rgba(11,23,32,.06))" }}>
        <div className="card-head" style={{ background: "var(--b50)", borderBottom: "1px solid var(--b100)" }}>
          <div className="ch-l">
            <h3>{isMorningReport ? window.t("Morning report") : window.t("Evening report")}</h3>
            <div className="ch-sub">{fmtDate(todayISO)} · {isMorningReport ? window.t("Offloaded by client today") : window.t("Delivered by client today")}</div>
          </div>
          <Segmented options={["Morning", "Evening"]} value={reportPhase} onChange={setReportPhase} />
        </div>
        <div className="card-body">
          {reportRows.length === 0 ? (
            <div style={{ padding: "20px 4px", fontSize: 12.5, color: "var(--muted)", textAlign: "center" }}>
              {window.t("Nothing logged today yet.")} <button className="btn ghost sm" onClick={() => opsNav("log")} style={{ marginInlineStart: 6 }}>{window.t("Open daily log")}</button>
            </div>
          ) : (
            <>
              {reportRows.map((m, i) => (
                <div key={m.client} style={{ display: "flex", alignItems: "center", gap: 12, padding: "10px 2px", borderBottom: i < reportRows.length - 1 ? "1px solid var(--border-soft)" : "0" }}>
                  <span className="mono muted" style={{ width: 20, textAlign: "right", fontSize: 12 }}>{i + 1}.</span>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontWeight: 600, fontSize: 13 }}>{m.client}</div>
                    <div style={{ fontSize: 11, color: "var(--muted)" }}>
                      {m.couriers} {window.t("couriers")}
                      {!isMorningReport && m.offloaded > 0 && <span> · {rate(m.delivered, m.offloaded)}%</span>}
                    </div>
                  </div>
                  <div className="mono" style={{ fontSize: 14, fontWeight: 600 }}>
                    {fmtNum(isMorningReport ? m.offloaded : m.delivered)}
                    <span className="muted" style={{ fontSize: 11, fontWeight: 400 }}> {isMorningReport ? window.t("offloaded") : window.t("delivered")}</span>
                  </div>
                </div>
              ))}
              <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "12px 2px 2px", marginTop: 4, borderTop: "2px solid var(--border)" }}>
                <span style={{ fontWeight: 700, fontSize: 13 }}>{isMorningReport ? window.t("Total collected today") : window.t("Total delivered today")}</span>
                <span className="mono" style={{ fontSize: 18, fontWeight: 700, color: "var(--b700)" }}>{fmtNum(reportTotal)}</span>
              </div>
              {isMorningReport &&
                <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "8px 2px 2px" }}>
                  <span style={{ fontWeight: 700, fontSize: 13 }}>{window.t("Total couriers")}</span>
                  <span className="mono" style={{ fontSize: 18, fontWeight: 700, color: "var(--b700)" }}>{fmtNum(reportRows.reduce((a, m) => a + (m.couriers || 0), 0))}</span>
                </div>
              }
            </>
          )}
        </div>
      </div>

      <div>
        {/* Chart */}
        <div className="card" data-tour="chart">
          <div className="card-head">
            <div className="ch-l">
              <h3>{window.t("Offloaded vs Delivered")}</h3>
              <div className="ch-sub">{window.t(rangeLabel)} · {window.t("all cities")}</div>
            </div>
            <div className="row-gap">
              <span style={{ display: "inline-flex", gap: 12, fontSize: 11, color: "var(--muted)" }}>
                <span><span className="dot" style={{ background: "var(--warn)" }} /> Offloaded</span>
                <span><span className="dot" style={{ background: "var(--good)" }} /> Delivered</span>
              </span>
              <Segmented options={["7D", "30D", "90D", "MAX"]} value={range} onChange={setRange} />
            </div>
          </div>
          <div className="card-body" style={{ paddingTop: 8 }}>
            <div style={{ height: 240 }}>
              <ResponsiveContainer width="100%" height="100%">
                <AreaChart data={chartData} margin={{ top: 8, right: 10, left: -16, bottom: 0 }}>
                  <defs>
                    <linearGradient id="gOff" x1="0" y1="0" x2="0" y2="1">
                      <stop offset="0%" stopColor="#F59E0B" stopOpacity={0.22} />
                      <stop offset="100%" stopColor="#F59E0B" stopOpacity={0} />
                    </linearGradient>
                    <linearGradient id="gDel" x1="0" y1="0" x2="0" y2="1">
                      <stop offset="0%" stopColor="#10B981" stopOpacity={0.26} />
                      <stop offset="100%" stopColor="#10B981" stopOpacity={0} />
                    </linearGradient>
                  </defs>
                  <CartesianGrid strokeDasharray="3 3" stroke="var(--border-soft)" vertical={false} />
                  <XAxis dataKey="d" tick={tickStyle} axisLine={false} tickLine={false} minTickGap={20} />
                  <YAxis tick={tickStyle} axisLine={false} tickLine={false} width={42} />
                  <Tooltip contentStyle={tipStyle} />
                  <Area type="monotone" dataKey="off" name="Offloaded" stroke="#F59E0B" strokeWidth={2} fill="url(#gOff)" isAnimationActive={!(window.BUSCO_PREFS && window.BUSCO_PREFS.reduceMotion)} />
                  <Area type="monotone" dataKey="del" name="Delivered" stroke="#10B981" strokeWidth={2} fill="url(#gDel)" isAnimationActive={!(window.BUSCO_PREFS && window.BUSCO_PREFS.reduceMotion)} />
                </AreaChart>
              </ResponsiveContainer>
            </div>
          </div>
        </div>

      </div>

      {/* Client snapshot — now a denser table */}
      <div>
        <div className="sec" data-tour="hub-clients">
          <h2>{window.t("Client performance")} <span className="ct">{CLIENT_ROWS.length}</span></h2>
          <div className="sec-right">
            <span className="muted" style={{ fontSize: 11.5 }}>{window.t("All-time rate · click to open detail")}</span>
          </div>
        </div>
        <div className="tbl-wrap">
          <table className="data">
            <thead>
              <tr>
                <th>{window.t("Client")}</th>
                <th>{window.t("Cities")}</th>
                <th className="num">{window.t("Offloaded")}</th>
                <th className="num">{window.t("Delivered")}</th>
                <th className="num">{window.t("Returned")}</th>
                <th>{window.t("Last 6 mo")}</th>
                <th style={{ width: 220 }}>{window.t("Rate")}</th>
              </tr>
            </thead>
            <tbody>
              {CLIENT_ROWS.map((c) =>
              <tr key={c.id} className={c.rate < 75 ? "row-bad" : ""}>
                  <td className="strong">{c.name}</td>
                  <td className="muted" style={{ fontSize: 11.5 }}>{c.cities.map((x) => x.name).join(" · ")}</td>
                  <td className="num">{fmtNum(c.offloaded)}</td>
                  <td className="num" style={{ color: "var(--good-700)" }}>{fmtNum(c.delivered)}</td>
                  <td className="num" style={{ color: c.rate < 75 ? "var(--crit-700)" : "var(--text)" }}>{fmtNum(c.returned)}</td>
                  <td><Sparkline values={CLIENT_SPARKS[c.id]} /></td>
                  <td><RateCell r={c.rate} /></td>
                </tr>
              )}
            </tbody>
            {CLIENT_ROWS.length > 0 && (() => {
              const tOff = CLIENT_ROWS.reduce((a, c) => a + c.offloaded, 0);
              const tDel = CLIENT_ROWS.reduce((a, c) => a + c.delivered, 0);
              const tRet = CLIENT_ROWS.reduce((a, c) => a + c.returned, 0);
              return (
                <tfoot>
                  <tr className="row-total">
                    <td className="strong">{window.t("Total")}</td>
                    <td className="muted" style={{ fontSize: 11.5 }}>{CLIENT_ROWS.length} {window.t("clients")}</td>
                    <td className="num strong">{fmtNum(tOff)}</td>
                    <td className="num strong" style={{ color: "var(--good-700)" }}>{fmtNum(tDel)}</td>
                    <td className="num strong">{fmtNum(tRet)}</td>
                    <td></td>
                    <td><RateCell r={rate(tDel, tOff)} /></td>
                  </tr>
                </tfoot>
              );
            })()}
          </table>
        </div>
      </div>

      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16 }}>
        {/* Yesterday's activity */}
        <div className="card">
          <div className="card-head">
            <div className="ch-l">
              <h3>{window.t("Yesterday's activity")}</h3>
              <div className="ch-sub">{yesterdayRuns.length} {window.t("entries logged")} · {window.t("offloaded")}</div>
            </div>
            <button className="btn sm" onClick={() => opsNav("log")}>{window.t("View all")}</button>
          </div>
          <div style={{ display: "flex", flexDirection: "column" }}>
            {yesterdayRuns.length === 0 ? (
              <div style={{ padding: "22px 16px", fontSize: 12, color: "var(--muted)", textAlign: "center" }}>{window.t("Nothing recorded yesterday.")}</div>
            ) : yesterdayRuns.slice(0, 5).map((e) => {
              const r = e.delivered > 0 ? rate(e.delivered, e.offloaded) : null;
              return (
                <div key={e.id} style={{ display: "flex", alignItems: "center", gap: 10, padding: "10px 16px", borderTop: "1px solid var(--border-soft)" }}>
                  <SourceBadge s={e.source} />
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontSize: 12.5, fontWeight: 600 }}>{e.client} <span className="muted" style={{ fontWeight: 400 }}>· {e.city} · {e.warehouse}</span></div>
                    <div style={{ fontSize: 11, color: "var(--muted)" }}>
                      {e.courierCount
                        ? `${e.courierCount} ${window.t(e.courierCount === 1 ? "courier" : "couriers")}`
                        : (e.courier && e.courier !== "—" ? e.courier : "—")}
                    </div>
                  </div>
                  <div className="mono" style={{ fontSize: 11.5, color: "var(--muted)" }}>
                    <b style={{ color: "var(--text)" }}>{e.offloaded}</b> {window.t("off")}
                  </div>
                  {r !== null ? <RateBadge r={r} /> : <span className="badge badge-slate">{window.t("Pending")}</span>}
                </div>);

            })}
          </div>
        </div>

        {/* By city — yesterday */}
        <div className="card">
          <div className="card-head">
            <div className="ch-l">
              <h3>{window.t("City performance · yesterday")}</h3>
              <div className="ch-sub">{window.t("Offloaded by city")}</div>
            </div>
          </div>
          {yesterdayCities.length === 0 ? (
            <div className="card-body">
              <div style={{ padding: "18px 0", fontSize: 12, color: "var(--muted)", textAlign: "center" }}>{window.t("Nothing recorded yesterday.")}</div>
            </div>
          ) : (
            <div className="tbl-wrap" style={{ border: 0 }}>
              <table className="data">
                <thead>
                  <tr>
                    <th>{window.t("City")}</th>
                    <th className="num">{window.t("Off")}</th>
                    <th className="num">{window.t("Del")}</th>
                    <th className="num">{window.t("Ret")}</th>
                    <th className="num">{window.t("Couriers")}</th>
                    <th className="num">{window.t("Rate")}</th>
                  </tr>
                </thead>
                <tbody>
                  {yesterdayCities.map((row) => {
                    const r = row.del > 0 ? rate(row.del, row.off) : null;
                    return (
                      <tr key={row.city}>
                        <td className="strong">{row.city}</td>
                        <td className="num">{fmtNum(row.off)}</td>
                        <td className="num" style={{ color: "var(--good-700)" }}>{fmtNum(row.del)}</td>
                        <td className="num">{fmtNum(row.ret)}</td>
                        <td className="num">{row.couriers ? fmtNum(row.couriers) : "—"}</td>
                        <td className="num">{r !== null ? <RateBadge r={r} /> : <span className="muted" style={{ fontSize: 11 }}>{window.t("Pending")}</span>}</td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>
          )}
        </div>
      </div>
    </div>);

}

// ── OPERATIONS (Daily Log) ───────────────────────────────────
// Two-phase logging: in the MORNING you record what each run offloaded,
// in the EVENING you record what came back delivered. Both phases land on
// the same (date · client · city · warehouse) row so the run stays whole.
function DailyLogScreen({ onToast }) {
  const ENTRIES = useStore((s) => s.entries);
  const todayISO = new Date().toISOString().slice(0, 10);
  const [view, setView] = useState("Daily log");           // Daily log | Reconcile
  const [phase, setPhase] = useState("Morning");           // Morning | Evening
  const [date, setDate] = useState(todayISO);
  const [clientId, setClientId] = useState("");
  const [city, setCity] = useState("");
  const [warehouse, setWarehouse] = useState("");
  const [count, setCount] = useState("");
  const [courierCount, setCourierCount] = useState("");
  const [pasteOpen, setPasteOpen] = useState(false);
  const [delTarget, setDelTarget] = useState(null);
  const [selected, setSelected] = useState([]);          // entry ids ticked for bulk delete
  const [bulkDel, setBulkDel] = useState(false);         // bulk-delete confirm open
  const [sourceFilter, setSourceFilter] = useState("All");
  const [filters, setFilters] = useState({ client: [], city: [] });
  // Set when arriving via the "entries missing delivered" warning — highlights
  // incomplete entries and sorts them to the top.
  const [flagIncomplete, setFlagIncomplete] = useState(false);
  useEffect(() => {
    const h = () => setFlagIncomplete(true);
    window.addEventListener("busco:flag-incomplete", h);
    return () => window.removeEventListener("busco:flag-incomplete", h);
  }, []);

  const isMorning = phase === "Morning";
  const client = CLIENTS.find((c) => c.id === clientId);
  const cities = client ? client.cities : [];
  const warehouses = (cities.find((x) => x.name === city) || {}).warehouses || [];

  // QOL: if the picked client serves only one city, or a city has only one
  // warehouse, select it automatically — nothing to click when there's no choice.
  useEffect(() => { if (client && client.cities.length === 1) setCity(client.cities[0].name); }, [clientId]);
  useEffect(() => { if (city && warehouses.length === 1) setWarehouse(warehouses[0]); }, [city, clientId]);

  // In the evening, show the run already logged this morning (so the user can
  // sanity-check delivered ≤ offloaded before saving).
  const matchMorning = (!isMorning && client && city && warehouse)
    ? ENTRIES.find((e) => e.date === date && e.client === client.name && e.city === city && e.warehouse === warehouse)
    : null;
  const countN = parseInt(count) || 0;
  const liveRate = (matchMorning && matchMorning.offloaded > 0) ? rate(countN, matchMorning.offloaded) : null;

  const reset = () => { setClientId(""); setCity(""); setWarehouse(""); setCount(""); setCourierCount(""); };
  // QOL: after a save keep the client + city selected so logging several
  // warehouses for the same client in a row is quick (Clear still wipes all).
  const resetForNext = () => { setWarehouse(""); setCount(""); setCourierCount(""); };

  const [saving, setSaving] = useState(false);
  const save = async () => {
    if (!clientId || !city || !warehouse || !count) {
      onToast("Fill all required fields", "danger");
      return;
    }
    // Courier count is required in the morning (it's how many couriers took the load).
    if (isMorning && (courierCount === "" || courierCount === null)) {
      onToast("Enter the courier count", "danger");
      return;
    }
    if (saving) return;
    setSaving(true);
    const clientName = (CLIENTS.find((c) => c.id === clientId) || {}).name || "";
    try {
      const r = await Store.saveDailyLog({
        phase: isMorning ? "morning" : "evening",
        date, client: clientName, city, warehouse, count: countN,
        courierCount: isMorning ? courierCount : undefined,
      });
      onToast(isMorning
        ? `Morning offload saved (${countN}) — ${clientName}`
        : `Evening delivered saved (${countN}) — ${clientName}`);
      resetForNext();
    } catch (err) {
      onToast(err?.message || "Failed to save entry", "danger");
    } finally {
      setSaving(false);
    }
  };

  const filtered = ENTRIES.filter((e) => {
    if (sourceFilter !== "All" && e.source !== sourceFilter.toLowerCase()) return false;
    if (filters.client.length && !filters.client.includes(e.client)) return false;
    if (filters.city.length && !filters.city.includes(e.city)) return false;
    return true;
  });
  const isIncomplete = (e) => e.date < todayISO && e.offloaded > 0 && e.delivered === 0 && e.source === "manual";
  const displayRows = flagIncomplete
    ? [...filtered].sort((a, b) => (isIncomplete(b) ? 1 : 0) - (isIncomplete(a) ? 1 : 0))
    : filtered;
  const clientOptions = [...new Set(ENTRIES.map((e) => e.client))];

  // Multi-select (bulk delete) over the rows currently shown.
  const toggleSelect = (id) => setSelected((s) => s.includes(id) ? s.filter((x) => x !== id) : [...s, id]);
  const allSelected = displayRows.length > 0 && displayRows.every((e) => selected.includes(e.id));
  const toggleAll = () => setSelected(allSelected ? [] : displayRows.map((e) => e.id));
  const bulkDelete = async () => {
    try {
      await Store.deleteEntries(selected);
      onToast(`${selected.length} ${window.t(selected.length === 1 ? "entry deleted" : "entries deleted")}`, "danger");
      setSelected([]);
    } catch (err) {
      onToast(err?.message || "Delete failed", "danger");
    } finally { setBulkDel(false); }
  };
  const cityOptions = [...new Set(ENTRIES.map((e) => e.city))];

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
      <div className="sec no-pad">
        <h2>{view === "Reconcile" ? window.t("Reconciliation") : window.t("Daily log")}</h2>
        <div className="sec-right" data-tour="reconcile">
          <Segmented options={["Daily log", "Reconcile"]} value={view} onChange={setView} />
        </div>
      </div>

      {view === "Reconcile" ? <ReconciliationView /> : (
    <div style={{ display: "grid", gridTemplateColumns: "440px 1fr", gap: 18 }}>
      {/* Form + the client's courier-report upload */}
      <div style={{ display: "flex", flexDirection: "column", gap: 18, alignSelf: "start" }}>
      <div className="card" data-tour="log-form">
        <div className="card-head">
          <div className="ch-l">
            <h3>{isMorning ? window.t("Morning report") : window.t("Evening report")}</h3>
            <div className="ch-sub">{isMorning ? window.t("How many parcels were offloaded (collected) today") : window.t("How many parcels were delivered today")}</div>
          </div>
          {liveRate !== null && <RateBadge r={liveRate} size="lg" />}
        </div>
        <div className="card-body" style={{ display: "flex", flexDirection: "column", gap: 12 }}>
          <div className="field" data-tour="phase">
            <label>{window.t("Report phase")}</label>
            <div className="segmented" style={{ width: "100%" }}>
              <button className={isMorning ? "on" : ""} onClick={() => { setPhase("Morning"); setCount(""); }} style={{ flex: 1 }}>
                <Icon name="package" size={12} /> {window.t("Morning")}
              </button>
              <button className={!isMorning ? "on" : ""} onClick={() => { setPhase("Evening"); setCount(""); }} style={{ flex: 1 }}>
                <Icon name="check-circle" size={12} /> {window.t("Evening")}
              </button>
            </div>
          </div>
          <div className="field-row c2">
            <div className="field">
              <label>{window.t("Date")}</label>
              <input type="date" value={date} onChange={(e) => setDate(e.target.value)} />
            </div>
            <div className="field">
              <label>{window.t("Client")}</label>
              <select value={clientId} onChange={(e) => {setClientId(e.target.value);setCity("");setWarehouse("");}}>
                <option value="">Select client…</option>
                {CLIENTS.map((c) => <option key={c.id} value={c.id}>{c.name}</option>)}
              </select>
            </div>
          </div>
          <div className="field-row c2">
            <div className="field">
              <label>{window.t("City")}</label>
              <select value={city} disabled={!client} onChange={(e) => {setCity(e.target.value);setWarehouse("");}}>
                <option value="">{client ? "Select city…" : "Pick client"}</option>
                {cities.map((c) => <option key={c.name}>{c.name}</option>)}
              </select>
            </div>
            <div className="field">
              <label>{window.t("Warehouse")}</label>
              {city && warehouses.length === 0 ? (
                // Client has no warehouses saved for this city — let the user
                // type one instead of dead-ending on an empty dropdown.
                <input value={warehouse} onChange={(e) => setWarehouse(e.target.value)} placeholder={window.t("Type warehouse name…")} />
              ) : (
                <select value={warehouse} disabled={!city} onChange={(e) => setWarehouse(e.target.value)}>
                  <option value="">{city ? "Select warehouse…" : "Pick city"}</option>
                  {warehouses.map((w) => <option key={w}>{w}</option>)}
                </select>
              )}
            </div>
          </div>
          {isMorning ? (
            <div className="field-row c2">
              <div className="field">
                <label>{window.t("Offloaded")}</label>
                <input type="number" min="0" className="mono" value={count} onChange={(e) => setCount(e.target.value)} onFocus={(e) => e.target.select()} placeholder="0" />
              </div>
              <div className="field">
                <label>{window.t("Courier count")}</label>
                <input type="number" min="0" className="mono" value={courierCount} onChange={(e) => setCourierCount(e.target.value)} onFocus={(e) => e.target.select()} placeholder="0" />
              </div>
            </div>
          ) : (
            <div className="field">
              <label>{window.t("Delivered")}</label>
              <input type="number" min="0" className="mono" value={count} onChange={(e) => setCount(e.target.value)} onFocus={(e) => e.target.select()} placeholder="0" />
            </div>
          )}

          {!isMorning && client && city && warehouse && (
            <div style={{ background: matchMorning ? "var(--b50)" : "var(--warn-50)", border: "1px solid " + (matchMorning ? "var(--b100)" : "var(--warn-100)"), borderRadius: "var(--r-sm)", padding: "9px 11px", fontSize: 11.5, color: matchMorning ? "var(--b700)" : "var(--warn-700)", display: "flex", gap: 7, alignItems: "flex-start" }}>
              <Icon name="info" size={12} color={matchMorning ? "var(--b700)" : "var(--warn-700)"} />
              <span>{matchMorning
                ? `${window.t("Morning offloaded")}: ${matchMorning.offloaded}. ${window.t("Returned will be")} ${Math.max(0, matchMorning.offloaded - countN)}.`
                : window.t("No morning offload logged for this client/warehouse yet — saving will create one with offloaded 0.")}</span>
            </div>
          )}

          <div style={{ display: "flex", alignItems: "center", justifyContent: "flex-end", gap: 8, paddingTop: 4 }}>
            <button className="btn sm" onClick={reset} disabled={saving}>{window.t("Clear")}</button>
            <button className="btn primary sm" onClick={save} disabled={saving}>
              {saving ? <span className="spinner" /> : null}
              {saving ? t("Saving…") : t("Save entry")}
            </button>
          </div>
        </div>
      </div>

      <CourierReportUpload onToast={onToast} onPaste={() => setPasteOpen(true)} />
      </div>

      {/* Recent entries */}
      <div>
        <div className="sec no-pad" data-tour="entries">
          <h2>{t("Recent entries")} <span className="ct">{filtered.length}</span></h2>
          <div className="sec-right">
            {selected.length > 0 &&
              <button className="btn sm" style={{ borderColor: "var(--crit-100)", color: "var(--crit-700)", background: "var(--crit-50)" }}
                onClick={() => setBulkDel(true)}>
                <Icon name="trash" size={12} color="var(--crit-700)" /> {window.t("Delete")} ({selected.length})
              </button>
            }
            <Segmented options={["All", "Manual", "Upload"]} value={sourceFilter} onChange={setSourceFilter} />
            <FilterPopover
              groups={[
                { key: "client", label: "Client", options: clientOptions },
                { key: "city",   label: "City",   options: cityOptions }
              ]}
              value={filters}
              onChange={setFilters}
              onClear={() => setFilters({ client: [], city: [] })}
            />
            <ExportMenu includeBrief onToast={onToast}
              getRows={() => ({
                rows: filtered.map((e) => ({
                  Date: e.date, Client: e.client, City: e.city, Warehouse: e.warehouse,
                  Source: e.source, Offloaded: e.offloaded, Delivered: e.delivered,
                  Returned: e.returned, "Rate %": e.offloaded > 0 ? rate(e.delivered, e.offloaded) : "",
                })),
                filename: `busco-entries-${todayISO}`,
              })} />
          </div>
        </div>
        {flagIncomplete &&
          <div className="banner" style={{ background: "var(--warn-50)", borderColor: "var(--warn-100)", color: "var(--warn-700)", marginBottom: 10 }}>
            <Icon name="alert-circle" size={14} color="var(--warn-700)" />
            <div style={{ fontSize: 12 }}>{window.t("Highlighted entries are missing their evening delivered count — switch the form to Evening to complete them.")}</div>
            <button className="btn sm" style={{ marginLeft: "auto" }} onClick={() => setFlagIncomplete(false)}>{window.t("Clear")}</button>
          </div>
        }
        <div className="tbl-wrap">
          <table className="data">
            <thead>
              <tr>
                <th style={{ width: 30 }}><input type="checkbox" checked={allSelected} onChange={toggleAll} style={{ cursor: "pointer" }} /></th>
                <th style={{ width: 30 }}></th>
                <th>{window.t("Date")}</th>
                <th>{window.t("Client")}</th>
                <th>{window.t("City")}</th>
                <th>{window.t("Warehouse")}</th>
                <th className="num">{window.t("Couriers")}</th>
                <th className="num">{window.t("Off")}</th>
                <th className="num">{window.t("Del")}</th>
                <th>{window.t("Rate")}</th>
                <th style={{ width: 40 }}></th>
              </tr>
            </thead>
            <tbody>
              {displayRows.map((e) => {
                const r = rate(e.delivered, e.offloaded);
                return (
                  <tr key={e.id} style={selected.includes(e.id) ? { backgroundColor: "var(--b50)" } : (flagIncomplete && isIncomplete(e) ? { backgroundColor: "var(--warn-50)" } : undefined)}>
                    <td><input type="checkbox" checked={selected.includes(e.id)} onChange={() => toggleSelect(e.id)} style={{ cursor: "pointer" }} /></td>
                    <td><SourceBadge s={e.source} /></td>
                    <td className="mono" style={{ fontSize: 11.5 }} title={fmtDate(e.date)}>{fmtDateRel(e.date)}</td>
                    <td className="strong">{e.client}</td>
                    <td>{e.city}</td>
                    <td className="muted" style={{ fontSize: 11.5 }}>{e.warehouse}</td>
                    <td className="num">{e.courierCount ? fmtNum(e.courierCount) : "—"}</td>
                    <td className="num">{e.offloaded}</td>
                    <td className="num">{e.delivered}</td>
                    <td><RateBadge r={r} /></td>
                    <td>
                      <button className="btn ghost sm" title={window.t("Delete entry")} onClick={() => setDelTarget(e)}>
                        <Icon name="trash" size={12} color="var(--crit)" />
                      </button>
                    </td>
                  </tr>);

              })}
            </tbody>
          </table>
        </div>
      </div>
    </div>
      )}
      {pasteOpen && <PasteReportModal onClose={() => setPasteOpen(false)} onToast={onToast} />}
      {delTarget &&
        <ConfirmModal
          title={window.t("Delete this entry?")}
          body={`${delTarget.client} · ${delTarget.city} · ${fmtDate(delTarget.date)} — ${delTarget.offloaded} ${window.t("off")} / ${delTarget.delivered} ${window.t("del")}. ${window.t("This can't be undone.")}`}
          confirmLabel={window.t("Delete entry")}
          tone="danger"
          onConfirm={() => { Store.deleteEntry(delTarget.id).then(() => onToast("Entry deleted", "danger")).catch((err) => onToast(err?.message || "Delete failed", "danger")); }}
          onClose={() => setDelTarget(null)}
        />
      }
      {bulkDel &&
        <ConfirmModal
          title={window.t("Delete selected entries?")}
          body={`${selected.length} ${window.t(selected.length === 1 ? "entry" : "entries")} ${window.t("will be permanently removed. This can't be undone.")}`}
          confirmLabel={window.t("Delete")}
          tone="danger"
          onConfirm={bulkDelete}
          onClose={() => setBulkDel(false)}
        />
      }
    </div>);

}

// ── RECONCILIATION (manual daily log vs uploaded client report) ──
// Busco logs each run by hand (source 'manual'); the client's own report is
// uploaded as CSV/XLSX (source 'upload'). This lines the two up per
// date · client · warehouse and flags any mismatch — the whole reason the
// manual log exists.
function ReconciliationView() {
  const ENTRIES = useStore((s) => s.entries);
  const [filters, setFilters] = useState({ client: [], city: [] });
  const [onlyIssues, setOnlyIssues] = useState(true);

  // Group by date · client (the courier reports carry no warehouse, so the
  // comparison is at client level): manual = Busco's daily log totals,
  // upload = the client's courier report totals. Couriers compares the count
  // entered in the morning log vs the couriers listed in the report.
  const map = new Map();
  for (const e of ENTRIES) {
    const key = `${e.date}|${e.client}`;
    if (!map.has(key)) map.set(key, { date: e.date, client: e.client, manual: null, upload: null });
    const g = map.get(key);
    const b = e.source === "manual" ? "manual" : "upload";
    if (!g[b]) g[b] = { offloaded: 0, delivered: 0, returned: 0, couriers: 0, _names: new Set() };
    g[b].offloaded += e.offloaded; g[b].delivered += e.delivered; g[b].returned += e.returned;
    if (b === "manual") g[b].couriers += e.courierCount || 0;
    else if (e.courier && e.courier !== "—") g[b]._names.add(e.courier);
  }
  for (const g of map.values()) {
    if (g.upload) g.upload.couriers = g.upload._names.size;
  }

  let rows = [...map.values()].map((g) => {
    const m = g.manual, u = g.upload;
    const both = !!(m && u);
    const dOff = both ? m.offloaded - u.offloaded : null;
    const dDel = both ? m.delivered - u.delivered : null;
    const status = both ? ((dOff === 0 && dDel === 0) ? "matched" : "variance")
      : (m ? "missing-client" : "missing-log");
    return { ...g, both, dOff, dDel, status };
  }).sort((a, b) => b.date.localeCompare(a.date) || a.client.localeCompare(b.client));

  if (filters.client.length) rows = rows.filter((r) => filters.client.includes(r.client));
  const issueRows = rows.filter((r) => r.status !== "matched");
  const shown = onlyIssues ? issueRows : rows;

  const counts = {
    compared: rows.filter((r) => r.both).length,
    matched: rows.filter((r) => r.status === "matched").length,
    variance: rows.filter((r) => r.status === "variance").length,
    missing: rows.filter((r) => r.status === "missing-client" || r.status === "missing-log").length,
  };

  const clientOptions = [...new Set([...map.values()].map((g) => g.client))];

  const STATUS = {
    matched:        { label: window.t("Matched"),              cls: "badge-good",  tone: "var(--good-700)" },
    variance:       { label: window.t("Difference"),           cls: "badge-crit",  tone: "var(--crit-700)" },
    "missing-client": { label: window.t("No client report"),   cls: "badge-warn",  tone: "var(--warn-700)" },
    "missing-log":  { label: window.t("Not in daily log"),     cls: "badge-info",  tone: "var(--info-700)" },
  };

  const Delta = ({ v }) => {
    if (v === null || v === undefined) return <span className="muted-2">—</span>;
    if (v === 0) return <span className="mono" style={{ color: "var(--good-700)" }}>0</span>;
    return <span className="mono strong" style={{ color: "var(--crit-700)" }}>{v > 0 ? "+" : ""}{v}</span>;
  };
  const Pair = ({ a, b, field }) => (
    <span className="mono" style={{ fontSize: 11.5 }}>
      <b>{a == null ? "—" : a[field]}</b><span className="muted"> / {b == null ? "—" : b[field]}</span>
    </span>
  );

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
      <div className="banner" style={{ background: "var(--info-50)", borderColor: "var(--info-100)", color: "var(--info-700)" }}>
        <Icon name="info" size={15} color="var(--info-700)" />
        <div style={{ fontSize: 12.5 }}>
          {window.t("Compares what Busco logged by hand")} (<b>{window.t("manual")}</b>) {window.t("against the client's uploaded report")} (<b>{window.t("client")}</b>). {window.t("Each cell shows manual / client.")}
        </div>
      </div>

      <div className="kpi-row">
        <KPI label={window.t("Entries compared")} value={counts.compared} sub={window.t("have both sources")} icon="list" tint="var(--b50)" accent="var(--b600)" />
        <KPI label={window.t("Matched")} value={counts.matched} sub={window.t("numbers agree")} icon="check-circle" tint="var(--good-50)" accent="var(--good-700)" tone={counts.variance === 0 ? "good" : ""} />
        <KPI label={window.t("Differences")} value={counts.variance} sub={window.t("numbers disagree")} icon="alert" tint="var(--crit-50)" accent="var(--crit-700)" tone={counts.variance > 0 ? "bad" : ""} />
        <KPI label={window.t("Missing one side")} value={counts.missing} sub={window.t("logged or reported, not both")} icon="alert-circle" tint="var(--warn-50)" accent="var(--warn-700)" />
      </div>

      <div className="sec no-pad">
        <h2>{window.t("Reconciliation detail")} <span className="ct">{shown.length}</span></h2>
        <div className="sec-right">
          <button className={"btn sm" + (onlyIssues ? " primary" : "")} onClick={() => setOnlyIssues((v) => !v)}>
            <Icon name="filter" size={12} color={onlyIssues ? "#fff" : "var(--muted)"} /> {onlyIssues ? window.t("Differences only") : window.t("Showing all")}
          </button>
          <FilterPopover
            groups={[
              { key: "client", label: "Client", options: clientOptions },
            ]}
            value={filters}
            onChange={setFilters}
            onClear={() => setFilters({ client: [], city: [] })}
          />
        </div>
      </div>

      <div className="tbl-wrap">
        <table className="data">
          <thead>
            <tr>
              <th>{window.t("Date")}</th>
              <th>{window.t("Client")}</th>
              <th className="num">{window.t("Couriers")} <span className="muted" style={{ fontWeight: 400 }}>(M/C)</span></th>
              <th className="num">{window.t("Offloaded")} <span className="muted" style={{ fontWeight: 400 }}>(M/C)</span></th>
              <th className="num">Δ</th>
              <th className="num">{window.t("Delivered")} <span className="muted" style={{ fontWeight: 400 }}>(M/C)</span></th>
              <th className="num">Δ</th>
              <th>{window.t("Status")}</th>
            </tr>
          </thead>
          <tbody>
            {shown.length === 0 ? (
              <tr><td colSpan={8} style={{ textAlign: "center", padding: "22px 0", color: "var(--muted)" }}>
                {onlyIssues ? window.t("No differences — everything matches. 🎉") : window.t("No data to reconcile yet.")}
              </td></tr>
            ) : shown.map((r) => {
              const st = STATUS[r.status];
              return (
                <tr key={`${r.date}|${r.client}`} className={r.status === "variance" ? "row-bad" : ""}>
                  <td className="mono" style={{ fontSize: 11.5 }} title={fmtDate(r.date)}>{fmtDateRel(r.date)}</td>
                  <td className="strong">{r.client}</td>
                  <td className="num"><Pair a={r.manual} b={r.upload} field="couriers" /></td>
                  <td className="num"><Pair a={r.manual} b={r.upload} field="offloaded" /></td>
                  <td className="num"><Delta v={r.dOff} /></td>
                  <td className="num"><Pair a={r.manual} b={r.upload} field="delivered" /></td>
                  <td className="num"><Delta v={r.dDel} /></td>
                  <td><span className={"badge " + st.cls}>{st.label}</span></td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>
    </div>
  );
}

// ── Courier report upload (Hub) ──────────────────────────────
// The client sends a per-courier report the day after. Pick the client and
// date, upload the file(s) for that client's report type, and the importer
// matches couriers by the ID the client assigned them (Couriers tab →
// per-client details), records their numbers, and feeds Reconcile.
function CourierReportUpload({ onToast, onPaste }) {
  const CLIENTS = useStore((s) => s.clients);
  const yesterdayISO = (() => { const d = new Date(); d.setDate(d.getDate() - 1); return d.toISOString().slice(0, 10); })();
  const [clientId, setClientId] = useState("");
  const [date, setDate] = useState(yesterdayISO);
  const [fileMain, setFileMain] = useState(null);
  const [filePpd, setFilePpd] = useState(null);
  const [fileCod, setFileCod] = useState(null);
  const [busy, setBusy] = useState(false);
  const [unmatched, setUnmatched] = useState(null);

  const client = (window.CLIENTS || []).find((c) => c.id === clientId);
  const type = client?.report_type || "";

  const FilePick = ({ label, file, onPick }) => (
    <label className="btn sm" style={{ display: "flex", alignItems: "center", gap: 6, cursor: "pointer", maxWidth: "100%" }}>
      <Icon name="upload" size={12} />
      <span style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{file ? file.name : label}</span>
      <input type="file" accept=".csv,.xlsx,.xls,.tsv" style={{ display: "none" }}
        onChange={(e) => { onPick(e.target.files?.[0] || null); e.target.value = ""; }} />
    </label>
  );

  const run = async () => {
    if (!client) { onToast("Pick a client first", "danger"); return; }
    if (busy) return;
    setBusy(true); setUnmatched(null);
    try {
      const r = await window.buscoImportCourierReport({
        clientName: client.name, date,
        files: type === "ajex-ksa" ? { ppd: filePpd, cod: fileCod } : { main: fileMain },
      });
      let msg = `${client.name}: ${r.imported} ${window.t("couriers imported")}`;
      if (r.skipped) msg += ` · ${r.skipped} ${window.t("non-Busco rows skipped")}`;
      onToast(msg);
      if (r.unmatched && r.unmatched.length) setUnmatched(r.unmatched);
      setFileMain(null); setFilePpd(null); setFileCod(null);
    } catch (e) {
      onToast(e?.message || "Import failed", "danger");
    } finally { setBusy(false); }
  };

  const ready = client && type && (type === "ajex-ksa" ? (filePpd && fileCod) : fileMain);

  return (
    <div className="card" data-tour="upload">
      <div className="card-head">
        <div className="ch-l">
          <h3>{window.t("Courier report upload")}</h3>
          <div className="ch-sub">{window.t("The client's per-courier report — usually for yesterday")}</div>
        </div>
        <button className="btn sm" onClick={onPaste}><Icon name="clipboard" size={12} /> {window.t("Paste report")}</button>
      </div>
      <div className="card-body" style={{ display: "flex", flexDirection: "column", gap: 12 }}>
        <div className="field-row c2">
          <div className="field">
            <label>{window.t("Client")}</label>
            <select value={clientId} onChange={(e) => { setClientId(e.target.value); setUnmatched(null); setFileMain(null); setFilePpd(null); setFileCod(null); }}>
              <option value="">{window.t("Select client…")}</option>
              {CLIENTS.map((c) => <option key={c.id} value={c.id}>{c.name}</option>)}
            </select>
          </div>
          <div className="field">
            <label>{window.t("Report date")}</label>
            <input type="date" value={date} onChange={(e) => setDate(e.target.value)} />
          </div>
        </div>

        {client && !type &&
          <div style={{ background: "var(--warn-50)", border: "1px solid var(--warn-100)", borderRadius: "var(--r-sm)", padding: "9px 11px", fontSize: 11.5, color: "var(--warn-700)" }}>
            {window.t("This client has no report type set — edit the client and choose one (e.g. Ajex KSA).")}
          </div>
        }

        {client && type === "ajex-ksa" &&
          <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
            <div style={{ fontSize: 11.5, color: "var(--muted)" }}>{window.t("Ajex KSA sends two sheets — upload both. Couriers not registered to Busco are skipped automatically.")}</div>
            <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
              <FilePick label={window.t("PPD file…")} file={filePpd} onPick={setFilePpd} />
              <FilePick label={window.t("COD file…")} file={fileCod} onPick={setFileCod} />
            </div>
          </div>
        }
        {client && type === "ajex-bh" &&
          <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
            <div style={{ fontSize: 11.5, color: "var(--muted)" }}>{window.t("Ajex (BH) sends one sheet — every courier in it should be Busco's.")}</div>
            <FilePick label={window.t("Report file…")} file={fileMain} onPick={setFileMain} />
          </div>
        }

        {unmatched &&
          <div style={{ background: "var(--crit-50)", border: "1px solid var(--crit-100)", borderRadius: "var(--r-sm)", padding: "9px 11px" }}>
            <div style={{ fontSize: 11.5, color: "var(--crit-700)", fontWeight: 700 }}>
              {unmatched.length} {window.t("courier ID(s) not recognised:")}
            </div>
            <div className="mono" style={{ fontSize: 11, color: "var(--crit-700)", marginTop: 4, wordBreak: "break-all" }}>{unmatched.join(", ")}</div>
            <div style={{ fontSize: 10.5, color: "var(--muted)", marginTop: 5 }}>{window.t("Add the missing IDs in Couriers → edit → per-client details, then re-upload.")}</div>
          </div>
        }

        <button className="btn primary sm" style={{ alignSelf: "flex-end" }} disabled={!ready || busy} onClick={run}>
          {busy ? <span className="spinner" /> : <Icon name="upload" size={12} color="#fff" />} {busy ? window.t("Importing…") : window.t("Import report")}
        </button>
      </div>
    </div>
  );
}

Object.assign(window, { HubScreen, DailyLogScreen, ReconciliationView, CourierReportUpload, tickStyle, tipStyle });