/* global React, Icon, Field, Button, Check, Tag, MetaCard, ImportBanner, runImportProgress, useToast, IMG_SLOTS, IMG_SKUS, SEED_IMG_WORKSHEET, PageHead, InfoNote, UserChip */
/* global WorksheetRow */
// L2-A — 批次調整工作表

const { useState, useEffect, useRef, useMemo, useCallback } = React;

const WS_LS_KEY = "ueImageAdjust_worksheet_v1";

const mkUid = () => `r-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,6)}`;

const mkRow = (skuId) => ({
  uid: mkUid(),
  skuId,
  drafts: {},
  statuses: {},
  errMsgs: {},
});

const saveDraft = (rows) => {
  if (rows.length === 0) { localStorage.removeItem(WS_LS_KEY); return; }
  localStorage.setItem(WS_LS_KEY, JSON.stringify({ rows, savedAt: Date.now() }));
};

const loadDraft = () => {
  try {
    const raw = localStorage.getItem(WS_LS_KEY);
    if (!raw) return null;
    return JSON.parse(raw);
  } catch { return null; }
};

// ── WorksheetMeta ───────────────────────────────────────────────────────────
const WorksheetMeta = ({ rows, totalChanges, currentUser }) => {
  const skuCount = rows.length;
  const summary = `${currentUser} · ${skuCount} 筆品項${totalChanges > 0 ? ` · ${totalChanges} 項未送出變更` : ""}`;
  return (
    <MetaCard summary={summary} sectionTitle="工作表資訊">
      <div className="meta-card__row">
        <dt>操作者</dt>
        <dd><UserChip name={currentUser} /></dd>
      </div>
      <div className="meta-card__row">
        <dt>工作表類型</dt>
        <dd>批次圖片調整</dd>
      </div>
      <div className="meta-card__row">
        <dt>品項筆數</dt>
        <dd><b>{skuCount}</b> 筆</dd>
      </div>
      <div className="meta-card__row">
        <dt>未送出變更</dt>
        <dd>{totalChanges > 0 ? `${totalChanges} 項` : "尚無變更"}</dd>
      </div>
      <div className="meta-card__row">
        <dt>送出後</dt>
        <dd>立即生效於商品主檔；無審核流程</dd>
      </div>
      <div className="meta-card__row">
        <dt>狀態</dt>
        <dd><Tag status="editing" /></dd>
      </div>
    </MetaCard>
  );
};


// ── ImageWorksheet (L2-A 主元件) ────────────────────────────────────────────
const ImageWorksheet = ({ initialSkus, currentUser, onBack, onDirtyChange }) => {
  const toast = useToast();

  const [rows,       setRows]       = useState([]);
  const [dirty,      setDirty]      = useState(false);
  const [expanded,   setExpanded]   = useState(new Set());
  const [selected,   setSelected]   = useState(new Set());
  const [search,     setSearch]     = useState("");

  const [bannerPhase,  setBannerPhase]  = useState(null);
  const [bannerTotal,  setBannerTotal]  = useState(0);
  const [bannerDone,   setBannerDone]   = useState(0);
  const [bannerTitle,  setBannerTitle]  = useState("");

  const [restored,      setRestored]      = useState(false);
  const [restoredCount, setRestoredCount] = useState(0);

  const [showMerge,   setShowMerge]   = useState(false);
  const [showSubmit,  setShowSubmit]  = useState(false);
  const [pendingSkus, setPendingSkus] = useState(null);

  const [addInput, setAddInput] = useState("");
  const [addErr,   setAddErr]   = useState("");
  const addInputRef  = useRef(null);
  const fileInputRef = useRef(null);

  const skuMap = useMemo(() => Object.fromEntries(IMG_SKUS.map(s => [s.skuId, s])), []);

  const totalChanges = useMemo(
    () => rows.reduce((n, r) => n + Object.keys(r.drafts).length, 0),
    [rows]
  );
  const errorRowCount = useMemo(
    () => rows.filter(r => Object.values(r.statuses).some(s => s === "err")).length,
    [rows]
  );
  const loadingRowCount = useMemo(
    () => rows.filter(r => Object.values(r.statuses).some(s => s === "loading")).length,
    [rows]
  );

  const filteredRows = useMemo(() => {
    const q = search.trim().toLowerCase();
    if (!q) return rows;
    return rows.filter(r => {
      const sku = skuMap[r.skuId];
      return r.skuId.toLowerCase().includes(q)
        || (sku?.name    || "").toLowerCase().includes(q)
        || (sku?.barcode || "").toLowerCase().includes(q);
    });
  }, [rows, search, skuMap]);

  const allExpanded = filteredRows.length > 0 && filteredRows.every(r => expanded.has(r.uid));
  const toggleAllExpand = () => {
    setExpanded(prev => {
      const s = new Set(prev);
      if (allExpanded) filteredRows.forEach(r => s.delete(r.uid));
      else             filteredRows.forEach(r => s.add(r.uid));
      return s;
    });
  };

  const allSelected = filteredRows.length > 0 && filteredRows.every(r => selected.has(r.uid));
  const anySelected = filteredRows.some(r => selected.has(r.uid));

  // ── localStorage ────────────────────────────────────────────────
  useEffect(() => {
    const draft = loadDraft();
    if (draft && draft.rows && draft.rows.length > 0) {
      if (initialSkus && initialSkus.length > 0) {
        setPendingSkus(initialSkus);
        setShowMerge(true);
        setRows(draft.rows);
        setRestored(true);
        setRestoredCount(draft.rows.length);
      } else {
        setRows(draft.rows);
        setRestored(true);
        setRestoredCount(draft.rows.length);
      }
    } else if (initialSkus && initialSkus.length > 0) {
      triggerPreload(initialSkus);
    } else {
      // 無草稿也非從列表帶入（fresh 瀏覽器 / 無痕 / 直接重整到工作表）→ 預載固定 seed，
      // 確保每台瀏覽器初次進來都看到同一組品項。seed 為 skuId 陣列，對照 IMG_SKUS。
      const seedRows = (SEED_IMG_WORKSHEET || [])
        .filter(id => skuMap[id])
        .map(id => mkRow(id));
      if (seedRows.length > 0) setRows(seedRows);
    }
  }, []);

  useEffect(() => { saveDraft(rows); }, [rows]);
  useEffect(() => () => { onDirtyChange?.(false); }, [onDirtyChange]);

  const markDirty = useCallback(() => {
    setDirty(true);
    onDirtyChange?.(true);
  }, [onDirtyChange]);

  // ── preload from list ────────────────────────────────────────────
  const triggerPreload = useCallback((skus) => {
    setBannerTitle("從列表帶入中…");
    setBannerPhase("parsing");
    setBannerTotal(skus.length);
    setBannerDone(0);
    const cancel = runImportProgress(skus.length, (d) => setBannerDone(d), () => {
      setRows(prev => {
        const existingIds = new Set(prev.map(r => r.skuId));
        const newRows = skus.filter(s => !existingIds.has(s.skuId)).map(s => mkRow(s.skuId));
        return [...prev, ...newRows];
      });
      setBannerPhase("ok");
      setBannerTotal(skus.length);
    });
    return cancel;
  }, []);

  // ── URL blur handler ─────────────────────────────────────────────
  const onUrlBlur = useCallback((uid, slotKey, value, oldUrl) => {
    if (value ? value !== oldUrl : !!oldUrl) markDirty();
    setRows(prev => prev.map(r => {
      if (r.uid !== uid) return r;
      const drafts   = { ...r.drafts };
      const statuses = { ...r.statuses };
      const errMsgs  = { ...r.errMsgs };

      if (!value) {
        if (oldUrl) {
          drafts[slotKey]   = "";
          statuses[slotKey] = null;
          delete errMsgs[slotKey];
        } else {
          delete drafts[slotKey];
          delete statuses[slotKey];
          delete errMsgs[slotKey];
        }
        return { ...r, drafts, statuses, errMsgs };
      }

      if (!/^https?:\/\//.test(value) && !/^data:/.test(value)) {
        drafts[slotKey]   = value;
        statuses[slotKey] = "err";
        errMsgs[slotKey]  = "URL 需以 http(s):// 開頭";
        return { ...r, drafts, statuses, errMsgs };
      }

      if (value === oldUrl) {
        delete drafts[slotKey];
        delete statuses[slotKey];
        delete errMsgs[slotKey];
        return { ...r, drafts, statuses, errMsgs };
      }

      drafts[slotKey]   = value;
      statuses[slotKey] = "loading";
      delete errMsgs[slotKey];

      setTimeout(() => {
        setRows(prev2 => prev2.map(r2 => {
          if (r2.uid !== uid) return r2;
          const s2 = { ...r2.statuses };
          const e2 = { ...r2.errMsgs };
          if (/broken|404|fail/i.test(value)) {
            s2[slotKey] = "err";
            e2[slotKey] = "圖片連結無法載入(404 / 連線錯誤)";
          } else {
            s2[slotKey] = "ok";
            delete e2[slotKey];
          }
          return { ...r2, statuses: s2, errMsgs: e2 };
        }));
      }, 700);

      return { ...r, drafts, statuses, errMsgs };
    }));
  }, [markDirty]);

  // ── revert single SKU ────────────────────────────────────────────
  const handleRevertSku = useCallback((uid) => {
    setRows(prev => prev.map(r =>
      r.uid !== uid ? r : { ...r, drafts: {}, statuses: {}, errMsgs: {} }
    ));
  }, []);

  // ── inline add ──────────────────────────────────────────────────
  const handleAdd = () => {
    const id = addInput.trim();
    if (!id) { setAddErr("請輸入品號"); return; }
    if (!skuMap[id]) { setAddErr(`查無品號 ${id}`); return; }
    if (rows.some(r => r.skuId === id)) { setAddErr(`品號 ${id} 已在工作表中`); return; }
    setRows(prev => [...prev, mkRow(id)]);
    markDirty();
    setAddInput("");
    setAddErr("");
    addInputRef.current?.focus();
  };

  // ── submit ───────────────────────────────────────────────────────
  const handleSubmitClick = () => {
    if (rows.length === 0) { toast.push({ type: "warning", msg: "工作表為空，請先加入品號" }); return; }
    if (totalChanges === 0) { toast.push({ type: "warning", msg: "尚未有任何變更可送出" }); return; }
    if (loadingRowCount > 0) { toast.push({ type: "warning", msg: "尚有圖片預覽載入中，請稍候" }); return; }
    if (errorRowCount > 0) { toast.push({ type: "danger", msg: `${errorRowCount} 筆品項有圖片連結錯誤，請修正後再送出` }); return; }
    setShowSubmit(true);
  };

  const handleConfirmSubmit = () => {
    setShowSubmit(false);
    setDirty(false);
    onDirtyChange?.(false);
    const now = new Date().toLocaleString("zh-TW", { hour12: false }).replace(",", "");
    rows.forEach(r => {
      const sku = skuMap[r.skuId];
      if (!sku) return;
      Object.entries(r.drafts).forEach(([k, v]) => { sku[k] = v || ""; });
      sku.lastUpdated = now.slice(0, 16);
      sku.updatedBy   = currentUser;
    });
    setRows([]);
    setExpanded(new Set());
    setSelected(new Set());
    toast.push({ type: "success", msg: `已送出 ${rows.length} 筆品項，共 ${totalChanges} 項圖片變更` });
    setTimeout(onBack, 600);
  };

  // ── merge dialog ─────────────────────────────────────────────────
  const handleMerge = (action) => {
    setShowMerge(false);
    if (action === "merge") {
      triggerPreload(pendingSkus.filter(s => !rows.some(r => r.skuId === s.skuId)));
    } else if (action === "replace") {
      setRows([]);
      setRestored(false);
      triggerPreload(pendingSkus);
    }
    setPendingSkus(null);
  };

  // ── import ───────────────────────────────────────────────────────
  const handleImport = (parsed) => {
    const total = parsed.length;
    setBannerTitle("Excel 解析中…");
    setBannerPhase("parsing");
    setBannerTotal(total);
    setBannerDone(0);
    runImportProgress(total, d => setBannerDone(d), () => {
      setRows(prev => {
        const existingIds = new Set(prev.map(r => r.skuId));
        const newRows = parsed
          .filter(p => !existingIds.has(p.skuId) && skuMap[p.skuId])
          .map(p => {
            const r = mkRow(p.skuId);
            if (p.drafts) {
              Object.assign(r.drafts, p.drafts);
              Object.keys(p.drafts).forEach(k => { r.statuses[k] = "ok"; });
            }
            return r;
          });
        const skipped = parsed.length - newRows.length;
        setBannerPhase(skipped > 0 ? "error" : "ok");
        return [...prev, ...newRows];
      });
      markDirty();
    });
  };

  const handleFileSelect = (e) => {
    if (!e.target.files || !e.target.files[0]) return;
    const mock = IMG_SKUS.slice(0, 6).map(s => ({ skuId: s.skuId, drafts: {} }));
    handleImport(mock);
    e.target.value = "";
  };

  return (
    <>
      {/* Header */}
      <PageHead
        crumbs={[
          { label: "商品調整" },
          { label: "商品圖片調整", onClick: onBack },
          { label: "批次調整圖片", current: true },
        ]}
        title={<>批次調整圖片 <Tag status="editing" /></>}
        dirty={dirty}
        actions={<>
          <Button variant="default" icon="download">下載匯入格式</Button>
          <Button variant="default" icon="upload" onClick={() => fileInputRef.current?.click()}>匯入 Excel</Button>
          <Button variant="secondary" disabled={rows.length === 0} onClick={() => { saveDraft(rows); setDirty(false); onDirtyChange?.(false); toast.push({ type: "success", msg: "草稿已儲存" }); }}>儲存草稿</Button>
          <Button variant="primary" icon="send" disabled={totalChanges === 0} onClick={handleSubmitClick}>送出{totalChanges > 0 ? `(${totalChanges})` : ""}</Button>
        </>}
      />

      {/* WorksheetMeta */}
      <WorksheetMeta rows={rows} totalChanges={totalChanges} currentUser={currentUser} />

      {/* 草稿還原 banner */}
      {restored && rows.length > 0 && (
        <div className="draft-restore-banner" style={{ margin: "12px 0 0" }}>
          <Icon name="check" size={16} />
          <div className="draft-restore-banner__main">
            <div className="draft-restore-banner__title">已自動還原上次的工作表（{restoredCount} 筆品項）</div>
          </div>
          <div className="draft-restore-banner__actions">
            <Button
              variant="text"
              size="sm"
              onClick={() => { setRows([]); setRestored(false); toast.push({ type: "success", msg: "草稿已清除" }); }}
            >清除草稿</Button>
            <Button variant="text" size="sm" iconOnly icon="close" onClick={() => setRestored(false)} />
          </div>
        </div>
      )}

      {/* Import banner */}
      {bannerPhase && (
        <div style={{ marginTop: 10 }}>
          <ImportBanner
            phase={bannerPhase}
            parsingTitle={bannerTitle}
            total={bannerTotal}
            done={bannerDone}
            onClose={() => setBannerPhase(null)}
          />
        </div>
      )}

      {/* 工作表主體 */}
      <div className="card" style={{ marginTop: 8 }}>
        {/* Toolbar */}
        <div className="ws-toolbar">
          <Field
            leading="search"
            placeholder="搜尋品號、品名、條碼…"
            value={search}
            onChange={e => setSearch(e.target.value)}
          />
          <span style={{ color: "var(--fg-3)", fontSize: 13, whiteSpace: "nowrap" }}>
            共 <b style={{ color: "var(--fg-1)" }}>{filteredRows.length}</b> 筆
            {totalChanges > 0 && <> · {totalChanges} 項變更</>}
            {errorRowCount > 0 && <> · <span style={{ color: "var(--danger)", fontWeight: 500 }}>{errorRowCount} 筆錯誤</span></>}
          </span>
          <div className="ws-toolbar__right">
            {rows.length > 0 && (
              <Button variant="default" size="sm" onClick={toggleAllExpand}>
                {allExpanded ? "全部收合" : "全部展開"}
              </Button>
            )}
          </div>
        </div>

        {/* Table */}
        <div className="tbl-wrap">
          {rows.length === 0 ? (
            <div className="ws-empty">
              <Icon name="image" size={56} className="ws-empty__icon" />
              <div className="ws-empty__title">尚無品項</div>
              <div className="ws-empty__desc">輸入品號加入，或從上方「匯入 Excel」批次匯入一整份 URL 名單。</div>
            </div>
          ) : (
            <table className="tbl--ws" style={{ tableLayout: "auto" }}>
              <colgroup>
                <col style={{ width: 36 }} />
                <col style={{ width: 140 }} />
                <col style={{ minWidth: 240 }} />
                <col style={{ width: 80 }} />
                {IMG_SLOTS.map(s => <col key={s.key} style={{ width: 60 }} />)}
                <col style={{ width: 120 }} />
                <col style={{ width: 48 }} />
              </colgroup>
              <thead>
                <tr>
                  <th style={{ textAlign: "center" }}>
                    <Check
                      checked={allSelected}
                      indeterminate={anySelected && !allSelected}
                      onChange={v => setSelected(prev => {
                        const s = new Set(prev);
                        filteredRows.forEach(r => v ? s.add(r.uid) : s.delete(r.uid));
                        return s;
                      })}
                    />
                  </th>
                  <th>品號</th>
                  <th>品名</th>
                  <th>促銷</th>
                  {IMG_SLOTS.map(s => <th key={s.key} style={{ textAlign: "center" }}>{s.label}</th>)}
                  <th>變更</th>
                  <th>操作</th>
                </tr>
              </thead>
              <tbody>
                {filteredRows.map(row => (
                  <WorksheetRow
                    key={row.uid}
                    row={row}
                    sku={skuMap[row.skuId]}
                    expanded={expanded.has(row.uid)}
                    selected={selected.has(row.uid)}
                    onToggleExpand={() => setExpanded(prev => {
                      const s = new Set(prev);
                      s.has(row.uid) ? s.delete(row.uid) : s.add(row.uid);
                      return s;
                    })}
                    onToggleSelect={() => setSelected(prev => {
                      const s = new Set(prev);
                      s.has(row.uid) ? s.delete(row.uid) : s.add(row.uid);
                      return s;
                    })}
                    onRemove={() => {
                      markDirty();
                      setRows(prev => prev.filter(r => r.uid !== row.uid));
                      setExpanded(prev => { const s = new Set(prev); s.delete(row.uid); return s; });
                      setSelected(prev => { const s = new Set(prev); s.delete(row.uid); return s; });
                    }}
                    onUrlBlur={onUrlBlur}
                    onRevertSku={() => handleRevertSku(row.uid)}
                  />
                ))}
              </tbody>
            </table>
          )}
        </div>

        {/* 新增品號列（tbl-wrap 外、card 內，對齊 adj-add-row 位置） */}
        <div className="ws-add-row">
          <Icon name="plus" size={16} />
          <span>新增品號</span>
          <input
            ref={addInputRef}
            className="ws-add-row__input"
            placeholder="輸入品號…"
            value={addInput}
            onChange={e => { setAddInput(e.target.value); setAddErr(""); }}
            onKeyDown={e => { if (e.key === "Enter") handleAdd(); }}
          />
          <Button variant="default" size="sm" onClick={handleAdd}>加入</Button>
          {addErr && <span className="ws-add-row__err">{addErr}</span>}
          {!addErr && <span style={{ color: "var(--fg-4)", fontSize: 12 }}>或從上方「匯入 Excel」批次加入</span>}
        </div>

      </div>

      {/* 隱藏 file input — 匯入 Excel 按鈕觸發 */}
      <input ref={fileInputRef} type="file" accept=".xlsx,.csv" style={{ display: "none" }} onChange={handleFileSelect} />

      {/* Merge Dialog */}
      {showMerge && (
        <div className="dialog-mask">
          <div className="dialog">
            <div className="dialog__head">
              <span className="dialog__title">工作表內已有品項</span>
            </div>
            <div className="dialog__body">
              <p style={{ font: "400 13px var(--font-sans)", color: "var(--fg-1)", margin: "0 0 8px" }}>
                工作表內已有草稿資料，同時又從列表帶入 {pendingSkus?.length || 0} 筆品項，請選擇處理方式：
              </p>
            </div>
            <div className="dialog__foot" style={{ justifyContent: "space-between" }}>
              <Button variant="text" onClick={() => { setShowMerge(false); setPendingSkus(null); }}>取消</Button>
              <div style={{ display: "flex", gap: 8 }}>
                <Button variant="default" onClick={() => handleMerge("merge")}>合併加入</Button>
                <Button variant="danger" onClick={() => handleMerge("replace")}>清空後改用 {pendingSkus?.length || 0} 筆</Button>
              </div>
            </div>
          </div>
        </div>
      )}

      {/* Submit Dialog */}
      {showSubmit && (
        <div className="dialog-mask">
          <div className="dialog">
            <div className="dialog__head">
              <span className="dialog__title">送出確認</span>
              <button className="dialog__close" onClick={() => setShowSubmit(false)}><Icon name="close" size={16} /></button>
            </div>
            <div className="dialog__body">
              <p style={{ font: "400 13px var(--font-sans)", color: "var(--fg-1)", margin: "0 0 8px" }}>
                將更新 <b>{rows.length}</b> 筆品項，共 <b>{totalChanges}</b> 項圖片變更。
              </p>
              <InfoNote variant="warning" style={{ marginTop: 8 }}>
                送出後立即生效於商品主檔。使用者於 Uber Eats App 將於下次菜單同步後看到新圖。送出後工作表會清空，如需保留請改點「儲存草稿」。
              </InfoNote>
            </div>
            <div className="dialog__foot">
              <Button variant="text" onClick={() => setShowSubmit(false)}>再檢查一次</Button>
              <Button variant="primary" onClick={handleConfirmSubmit}>確認送出</Button>
            </div>
          </div>
        </div>
      )}
    </>
  );
};

Object.assign(window, { ImageWorksheet, WorksheetMeta });
