/* WAREHOUSE 2.0 · 倉庫地圖 MAP / GIS — Swiss 版式,真後端(GIS-lite,無 maplibre) */
(() => {
const W2 = window.W2;
const { t } = window.W2_LANG;
window.W2_LANG.addEN({
  "倉庫 GIS 定位 · 庫區貨位統計 · 頁面只讀,定位與找貨交秘書": "Warehouse GIS · zone & slot statistics · read-only, locate & find via Secretary",
  "打開完整地圖": "Open full map",
  "倉庫地圖上現在有什麼要處理的?哪些倉庫還沒定位、哪些庫區有風險?": "Anything to handle on the warehouse map? Which warehouses lack GIS location, which zones are at risk?",
  "在管倉庫": "Warehouses",
  "座": "", "個": "",
  "庫存合計 {n}": "Total stock {n}",
  "未定位倉庫": "Unlocated",
  "讓秘書定位 →": "Locate via Secretary →",
  "全部已定位": "All located",
  "把還沒有 GIS 定位的倉庫列出來,逐個追問地址或經緯度後幫我保存定位": "List warehouses without GIS location; ask me for each address or coordinates, then save the locations",
  "庫區": "Zones",
  "共 {n} 個貨位": "{n} slots in total",
  "風險庫區": "Zones at risk",
  "無風險": "No risk",
  "分析有預警的庫區,按風險排序給我處置建議": "Analyse zones with alerts, rank by risk and give me resolution advice",
  "倉庫清單": "Warehouse register",
  "{n} 座 · 同一後端實時": "{n} warehouses · live from the same backend",
  "庫存分佈": "Stock distribution",
  "倉庫": "Warehouse", "編碼 / 類型": "Code / Type", "地址": "Address",
  "物資 / 庫存": "Items / Stock", "容量": "Capacity", "定位": "Location",
  "默認庫": "DEFAULT", "已定位": "Located", "未定位": "Unlocated", "未分類": "untyped",
  "定位倉庫": "Locate warehouse",
  "幫倉庫「{name}」設置 GIS 定位,請追問地址或經緯度後保存": "Set the GIS location for warehouse \"{name}\" — ask me for the address or coordinates, then save",
  "倉庫「{name}」現在的物資、庫存和預警情況怎麼樣?": "How are items, stock and alerts in warehouse \"{name}\" right now?",
  "還沒有倉庫資料": "No warehouses yet",
  "對秘書說「幫我登記一個倉庫」,或到完整地圖新建與定位。": "Tell the Secretary to register a warehouse, or create and locate one in the full map.",
  "幫我登記一個新倉庫,請追問名稱、類型和地址後辦理": "Register a new warehouse for me — ask for name, type and address, then proceed",
  "登記倉庫": "Register warehouse",
  "庫區與貨位": "Zones & slots",
  "{z} 個庫區 · {r} 個貨位": "{z} zones · {r} slots",
  "找物資位置": "Find an item",
  "幫我找物資的存放位置,請追問物資名稱後告訴我它在哪個倉庫、哪個庫位": "Find where an item is stored — ask me for the item name, then tell me its warehouse and slot",
  "{r} 貨位 · {i} 種": "{r} slots · {i} SKUs",
  "{n} 風險": "{n} at risk",
  "問這個庫區": "Ask about zone",
  "庫區「{name}」({id})現在存了哪些物資?有沒有低庫存或風險?": "What is stored in zone \"{name}\" ({id})? Any low stock or risks?",
  "還沒有庫區資料": "No zones yet",
  "對秘書說「幫我從庫存整理生成庫區與貨位」,或在完整地圖使用自動整理。": "Tell the Secretary to derive zones and slots from stock data, or use auto-layout in the full map.",
  "幫我從現有庫存資料自動整理生成庫區和貨位": "Derive zones and slots automatically from the current stock data",
  "讓秘書整理庫位": "Organise via Secretary",
  "載入中…": "Loading…",
  "互動地圖、畫區域、測距在完整地圖(經典版)中使用。": "Interactive map, area drawing and distance measuring live in the full map (Classic).",
});
const { useState: _s, useEffect: _e, useMemo: _mm } = React;
const { Icon: I, Btn: B, Tag: T, Label: LB, Empty: EM, Kpi, StackBar, Folio, Band, pad2, num } = W2;
const ask = (p) => W2.openSecretary(p);

/* 數量顯示:非數字給 —,大數帶千分位 */
const fq = (v) => {
  const n = Number(v);
  if (!Number.isFinite(n)) return "—";
  return (Math.round(n * 10) / 10).toLocaleString();
};
const capColor = (c) => c >= 90 ? "var(--red)" : c >= 70 ? "var(--warn)" : "var(--ink)";
/* 已定位 = lat/lng 同時存在且為有效數字(髒數據如 "" / "abc" 一律視為未定位,避免 NaN 上屏) */
const hasLL = (w) => w != null && w.lat != null && w.lng != null &&
  Number.isFinite(Number(w.lat)) && Number.isFinite(Number(w.lng));

const PageGis = ({ boot }) => {
  const [geo, setGeo] = _s(null); // null=載入中,之後恆為對象
  _e(() => { W2.json("/api/warehouses/geo").then((d) => setGeo(d || {})).catch(() => setGeo({})); }, []);

  const whs = (geo && Array.isArray(geo.warehouses)) ? geo.warehouses : [];
  const zones = (boot && Array.isArray(boot.ZONES)) ? boot.ZONES : [];
  const located = whs.filter(hasLL);
  const unlocated = whs.length - located.length;
  const totalRacks = zones.reduce((s, z) => s + num(z.racks), 0);
  const riskZones = zones.filter((z) => num(z.alert) > 0);
  const stockTotal = whs.reduce((s, w) => s + num(w.stock_total), 0);

  const stack = _mm(() => whs
    .map((w, i) => ({ value: num(w.stock_total), color: W2.CHART_COLORS[i % W2.CHART_COLORS.length], label: w.name || "—" }))
    .filter((d) => d.value > 0), [geo]);

  return (
    <>
      <Folio no="11" en="MAP / GIS" title={t("倉庫地圖")}
        sub={t("倉庫 GIS 定位 · 庫區貨位統計 · 頁面只讀,定位與找貨交秘書")}
        right={<>
          <a href={W2.CLASSIC_URL} className="btn" style={{ textDecoration: "none" }}><I name="map" size={14}/>{t("打開完整地圖")}</a>
          <B kind="primary" icon="sparkle" onClick={() => ask(t("倉庫地圖上現在有什麼要處理的?哪些倉庫還沒定位、哪些庫區有風險?"))}>{t("問秘書")}</B>
        </>}/>

      <div className="kpi-band">
        <Kpi label={t("在管倉庫")} value={whs.length} unit={t("座")} delay={0}
          foot={<><span className="muted" style={{ fontSize: 11.5 }}>{t("庫存合計 {n}", { n: fq(stockTotal) })}</span><T tone="plain">GEO</T></>}/>
        <Kpi label={t("未定位倉庫")} value={unlocated} unit={t("座")} red={unlocated > 0} delay={.05}
          foot={unlocated > 0
            ? <button className="tag redinv" style={{ cursor: "pointer" }} onClick={() => ask(t("把還沒有 GIS 定位的倉庫列出來,逐個追問地址或經緯度後幫我保存定位"))}>{t("讓秘書定位 →")}</button>
            : <T tone="ok" dot>{t("全部已定位")}</T>}/>
        <Kpi label={t("庫區")} value={zones.length} unit={t("個")} delay={.1}
          foot={<span className="muted" style={{ fontSize: 11.5 }}>{t("共 {n} 個貨位", { n: totalRacks })}</span>}/>
        <Kpi label={t("風險庫區")} value={riskZones.length} unit={t("個")} red={riskZones.length > 0} delay={.15}
          foot={riskZones.length
            ? <button className="tag bad" style={{ cursor: "pointer" }} onClick={() => ask(t("分析有預警的庫區,按風險排序給我處置建議"))}>{t("交秘書處置")}</button>
            : <T tone="ok" dot>{t("無風險")}</T>}/>
      </div>

      <Band no="A" title={t("倉庫清單")} sub={whs.length ? t("{n} 座 · 同一後端實時", { n: whs.length }) : ""} delay={.1}
        right={<B size="sm" icon="plus" onClick={() => ask(t("幫我登記一個新倉庫,請追問名稱、類型和地址後辦理"))}>{t("登記倉庫")}</B>}>
        {stack.length > 1 && (
          <div className="col g10" style={{ marginBottom: 20 }}>
            <LB dim>{t("庫存分佈")}</LB>
            <StackBar data={stack}/>
            <div className="row g16 wrap" style={{ fontSize: 11.5 }}>
              {stack.map((d) => (
                <span key={d.label} className="row g6">
                  <span style={{ width: 9, height: 9, background: d.color, flexShrink: 0 }}/>
                  <span className="ink2">{d.label}</span>
                  <span className="num" style={{ fontWeight: 700 }}>{fq(d.value)}</span>
                </span>
              ))}
            </div>
          </div>
        )}
        {whs.length ? (
          <div style={{ overflowX: "auto" }}>
            <table className="tbl2">
              <thead><tr>
                <th style={{ width: 40 }}>#</th><th>{t("倉庫")}</th><th>{t("編碼 / 類型")}</th><th>{t("地址")}</th>
                <th>{t("物資 / 庫存")}</th><th>{t("容量")}</th><th>{t("定位")}</th><th style={{ width: 96 }}>{t("交給秘書")}</th>
              </tr></thead>
              <tbody>
                {whs.map((w, i) => {
                  const hasGeo = hasLL(w);
                  const cap = Number(w.capacity_usage);
                  const hasCap = w.capacity_usage != null && Number.isFinite(cap);
                  return (
                    <tr key={w.id != null ? w.id : i}>
                      <td className="num muted">{pad2(i + 1)}</td>
                      <td>
                        <span className="row g8" style={{ fontWeight: 650 }}>
                          {w.name || "—"}{w.is_default ? <T tone="inv">{t("默認庫")}</T> : null}
                        </span>
                      </td>
                      <td>
                        <div className="col g4">
                          <span className="num" style={{ fontWeight: 600 }}>{w.code || "—"}</span>
                          <span className="muted" style={{ fontSize: 11 }}>{w.warehouse_type || t("未分類")}</span>
                        </div>
                      </td>
                      <td className="muted" style={{ fontSize: 12.5 }}>
                        <span style={{ display: "block", maxWidth: 220, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }} title={w.address || ""}>{w.address || "—"}</span>
                      </td>
                      <td>
                        <span className="num" style={{ fontWeight: 700, fontSize: 15 }}>{num(w.item_count)}</span>
                        <span className="muted" style={{ fontSize: 11.5 }}> {t("種")}</span>
                        <span className="num muted" style={{ fontSize: 11.5 }}> · {fq(w.stock_total)}</span>
                      </td>
                      <td>
                        {hasCap ? (
                          <>
                            <span className="num" style={{ fontWeight: 700, color: capColor(cap) }}>{Math.round(cap)}%</span>
                            <div className="bar" style={{ width: 76, marginTop: 5 }}>
                              <i style={{ width: Math.min(100, Math.max(0, cap)) + "%", background: capColor(cap) }}/>
                            </div>
                          </>
                        ) : <span className="muted">—</span>}
                      </td>
                      <td>
                        {hasGeo ? (
                          <div className="col g4">
                            <T tone="ok" dot>{t("已定位")}</T>
                            <span className="num muted" style={{ fontSize: 10.5 }}>{Number(w.lat).toFixed(4)}, {Number(w.lng).toFixed(4)}</span>
                          </div>
                        ) : <T tone="warn">{t("未定位")}</T>}
                      </td>
                      <td>
                        <div className="row g4">
                          <button className="btn sm" title={t("定位倉庫")} style={{ padding: "0 8px" }}
                            onClick={() => ask(t("幫倉庫「{name}」設置 GIS 定位,請追問地址或經緯度後保存", { name: w.name || "—" }))}><I name="map" size={12}/></button>
                          <button className="btn sm" title={t("問秘書")} style={{ padding: "0 8px" }}
                            onClick={() => ask(t("倉庫「{name}」現在的物資、庫存和預警情況怎麼樣?", { name: w.name || "—" }))}><I name="sparkle" size={12}/></button>
                        </div>
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        ) : geo === null ? (
          <div className="muted" style={{ padding: "28px 0", fontSize: 12.5 }}>{t("載入中…")}</div>
        ) : (
          <EM icon="map" title={t("還沒有倉庫資料")} sub={t("對秘書說「幫我登記一個倉庫」,或到完整地圖新建與定位。")}
            action={<div className="row g10">
              <B size="sm" icon="sparkle" onClick={() => ask(t("幫我登記一個新倉庫,請追問名稱、類型和地址後辦理"))}>{t("登記倉庫")}</B>
              <a href={W2.CLASSIC_URL} className="btn sm" style={{ textDecoration: "none" }}>{t("打開完整地圖")}</a>
            </div>}/>
        )}
      </Band>

      <Band no="B" title={t("庫區與貨位")} sub={zones.length ? t("{z} 個庫區 · {r} 個貨位", { z: zones.length, r: totalRacks }) : ""} delay={.15}
        right={<B size="sm" icon="search" onClick={() => ask(t("幫我找物資的存放位置,請追問物資名稱後告訴我它在哪個倉庫、哪個庫位"))}>{t("找物資位置")}</B>}>
        {zones.length ? (
          <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(230px, 1fr))", borderTop: "2px solid var(--rule)" }}>
            {zones.map((z, i) => {
              const cap = Math.min(100, Math.max(0, Math.round(num(z.cap))));
              const alert = num(z.alert);
              return (
                <div key={(z.id != null ? z.id : i) + ":" + i} className="col g8"
                  style={{ padding: "16px 16px 14px", borderRight: "1px solid var(--hair-soft)", borderBottom: "1px solid var(--hair-soft)" }}>
                  <div className="row spread">
                    <span className="mono" style={{ fontSize: 24, fontWeight: 700, letterSpacing: "-.02em" }}>{z.id || "—"}</span>
                    {alert > 0 ? <T tone="bad" dot>{t("{n} 風險", { n: alert })}</T> : <T tone="ok" dot>{t("正常")}</T>}
                  </div>
                  <div style={{ fontWeight: 650, fontSize: 13.5, lineHeight: 1.3 }}>{z.name || "—"}</div>
                  <div className="muted num" style={{ fontSize: 11.5 }}>{t("{r} 貨位 · {i} 種", { r: num(z.racks), i: num(z.items) })}</div>
                  <div className="row g8">
                    <div className="bar" style={{ flex: 1 }}><i style={{ width: cap + "%", background: capColor(cap) }}/></div>
                    <span className="num muted" style={{ fontSize: 11 }}>{cap}%</span>
                  </div>
                  <B size="sm" icon="sparkle" style={{ justifyContent: "flex-start" }}
                    onClick={() => ask(t("庫區「{name}」({id})現在存了哪些物資?有沒有低庫存或風險?", { name: z.name || "—", id: z.id || "—" }))}>{t("問這個庫區")}</B>
                </div>
              );
            })}
          </div>
        ) : (
          <EM icon="layers" title={t("還沒有庫區資料")} sub={t("對秘書說「幫我從庫存整理生成庫區與貨位」,或在完整地圖使用自動整理。")}
            action={<B size="sm" icon="sparkle" onClick={() => ask(t("幫我從現有庫存資料自動整理生成庫區和貨位"))}>{t("讓秘書整理庫位")}</B>}/>
        )}
        <div className="row g8" style={{ marginTop: 18 }}>
          <span className="mono muted" style={{ fontSize: 9.5, letterSpacing: ".18em" }}>GIS-LITE · FULL MAP IN CLASSIC</span>
          <span className="muted" style={{ fontSize: 11 }}>{t("互動地圖、畫區域、測距在完整地圖(經典版)中使用。")}</span>
        </div>
      </Band>
    </>
  );
};

window.W2.PAGES["gis"] = PageGis;
})();
