// === Product detail viewer ===
function ProductDetail({ productId, products, setProducts, setAllProducts, onClose, productsSource }) {
  const product = products.find(p => p.id === productId);
  if (!product) {
    console.warn("[ProductDetail] 상품 못 찾음. productId=", productId, "products.length=", products?.length);
    return (
      <window.Modal open={true} onClose={onClose} title="상품을 찾을 수 없음" size="md"
        footer={<button className="btn btn-primary" onClick={onClose}>닫기</button>}>
        <div style={{ padding: 20, textAlign: "center" }}>
          <window.I.AlertCircle size={32} stroke="var(--warning)" style={{ marginBottom: 8 }} />
          <div>ID <code>{productId}</code> 상품을 찾을 수 없습니다.</div>
          <div className="text-sm muted" style={{ marginTop: 8 }}>
            전체 상품 로드가 끝났는지 확인하거나, 새로고침 후 다시 시도해주세요.
          </div>
        </div>
      </window.Modal>
    );
  }
  const isLive = productsSource === "live";
  const cat = window.MOCK.CATEGORIES.find(c => c.id === product.category);
  const [tab, setTab] = useState("overview");
  const margin = product.costPrice > 0
    ? ((product.price - product.costPrice) / product.price * 100).toFixed(1)
    : null;

  // 라이브 모드: GET origin-product로 전체 상세 데이터 가져옴
  const [liveData, setLiveData] = useState(null);
  const [loadingLive, setLoadingLive] = useState(false);
  const [liveError, setLiveError] = useState(null);
  const [edits, setEdits] = useState({}); // { salePrice?, stockQuantity?, immediateDiscount?, name? }
  const [saving, setSaving] = useState(false);

  useEffect(() => {
    if (!isLive || !product.originProductNo) return;
    setLoadingLive(true);
    setLiveError(null);
    window.API.naverFetchOriginProduct(product.originProductNo)
      .then(data => setLiveData(data))
      .catch(err => {
        console.error("[detail-fetch]", err);
        setLiveError(err.message);
      })
      .finally(() => setLoadingLive(false));
  }, [isLive, product.originProductNo]);

  // 표시할 값 — 편집 중이면 edits, 아니면 liveData(라이브) 또는 product(mock)
  const liveOP = liveData?.originProduct;
  const cur = isLive && liveOP ? {
    name: liveOP.name,
    salePrice: liveOP.salePrice,
    stockQuantity: liveOP.stockQuantity,
    immediateDiscount: liveOP.customerBenefit?.immediateDiscountPolicy?.discountMethod?.value || 0,
    statusType: liveOP.statusType,
    detailContent: liveOP.detailContent || "",
    representativeImageUrl: liveOP.images?.representativeImage?.url || product.imageUrl,
    optionalImages: liveOP.images?.optionalImages || [],
    wholeCategoryName: product.categoryFull,
    leafCategoryId: liveOP.leafCategoryId,
  } : {
    name: product.name,
    salePrice: product.price,
    stockQuantity: product.stock,
    immediateDiscount: product.price - (product.discountedPrice || product.price),
    statusType: product.status === "active" ? "SALE" : "OUTOFSTOCK",
    detailContent: product.desc || "",
    representativeImageUrl: product.imageUrl,
    optionalImages: [],
    wholeCategoryName: cat?.name || "",
    leafCategoryId: product.category,
  };

  const get = (key) => edits[key] !== undefined ? edits[key] : cur[key];
  const isDirty = (key) => edits[key] !== undefined && edits[key] !== cur[key];
  const anyDirty = Object.keys(edits).some(k => edits[k] !== cur[k]);

  const currentDiscountedPrice = Math.max(0, (get("salePrice") || 0) - (get("immediateDiscount") || 0));

  const setEdit = (key, value) => setEdits(prev => ({ ...prev, [key]: value }));
  const clearEdits = () => setEdits({});

  // mock 저장 (기존 동작)
  const saveMock = () => {
    setProducts(prev => prev.map(p => {
      if (p.id !== product.id) return p;
      return {
        ...p,
        name: get("name"),
        price: get("salePrice"),
        stock: get("stockQuantity"),
        desc: get("detailContent"),
      };
    }));
    toast("저장되었습니다");
    onClose();
  };

  // 라이브 저장 — 변경된 필드만 PUT
  const saveLive = async () => {
    const changes = {};
    if (isDirty("name")) changes.name = get("name");
    if (isDirty("salePrice")) {
      const v = parseInt(get("salePrice"), 10);
      if (isNaN(v) || v < 0 || v % 10 !== 0) { toast("판매가는 10원 단위 정수여야 합니다"); return; }
      changes.salePrice = v;
    }
    if (isDirty("immediateDiscount")) {
      const v = parseInt(get("immediateDiscount"), 10);
      if (isNaN(v) || v < 0 || v % 10 !== 0) { toast("즉시할인은 10원 단위 정수여야 합니다"); return; }
      if (v > get("salePrice")) { toast("즉시할인이 판매가를 넘을 수 없습니다"); return; }
      changes.immediateDiscount = v;
    }
    if (isDirty("stockQuantity")) {
      const v = parseInt(get("stockQuantity"), 10);
      if (isNaN(v) || v < 0) { toast("재고는 0 이상이어야 합니다"); return; }
      changes.stockQuantity = v;
    }
    if (isDirty("detailContent")) {
      changes.detailContent = get("detailContent") || "";
    }
    if (Object.keys(changes).length === 0) { toast("변경된 내용이 없습니다"); return; }

    setSaving(true);
    try {
      await window.API.naverUpdateProduct(product.originProductNo, changes);
      // 로컬 products state 업데이트
      setProducts(prev => prev.map(p => {
        if (p.id !== product.id) return p;
        const newPrice = changes.salePrice !== undefined ? changes.salePrice : p.price;
        const newDiscount = changes.immediateDiscount !== undefined ? changes.immediateDiscount : (p.price - (p.discountedPrice || p.price));
        return {
          ...p,
          name: changes.name !== undefined ? changes.name : p.name,
          price: newPrice,
          stock: changes.stockQuantity !== undefined ? changes.stockQuantity : p.stock,
          discountedPrice: Math.max(0, newPrice - newDiscount),
          status: (changes.stockQuantity !== undefined && changes.stockQuantity === 0) ? "outofstock" : p.status,
        };
      }));
      toast("네이버에 저장되었습니다");
      onClose();
    } catch (err) {
      console.error("[detail-save]", err);
      toast("저장 실패: " + err.message);
    } finally {
      setSaving(false);
    }
  };

  const onSave = isLive ? saveLive : saveMock;
  const storeUrl = isLive && product.channelProductNo
    ? `https://smartstore.naver.com/main/products/${product.channelProductNo}`
    : "https://smartstore.naver.com";

  return (
    <Modal open={true} onClose={onClose} size="xl" title={
      <div className="row gap-3">
        <span style={{ fontSize: 11, color: "var(--text-subtle)", fontFamily: "monospace" }}>
          {isLive ? `#${product.originProductNo}` : product.sku}
        </span>
        <span>{get("name")}</span>
        {isLive && <span className="badge badge-success badge-dot">라이브</span>}
      </div>
    } footer={
      <>
        <a className="btn btn-ghost" target="_blank" rel="noreferrer" href={storeUrl}>
          <window.I.ExternalLink size={14} /> 스마트스토어에서 보기
        </a>
        <div className="right" />
        <button className="btn" onClick={onClose} disabled={saving}>닫기</button>
        <button className="btn btn-primary" onClick={onSave} disabled={saving || (isLive && !anyDirty)}>
          <window.I.Check size={14} /> {saving ? "저장 중..." : isLive ? "네이버에 저장" : "변경사항 저장"}
        </button>
      </>
    }>
      {isLive && loadingLive && (
        <div style={{ padding: 24, textAlign: "center", color: "var(--text-muted)" }}>
          네이버에서 상세 데이터 불러오는 중...
        </div>
      )}
      {isLive && liveError && (
        <div style={{ padding: 12, background: "rgba(239, 68, 68, 0.08)", border: "1px solid rgba(239, 68, 68, 0.35)", borderRadius: 6, marginBottom: 12, color: "var(--danger)" }}>
          상세 조회 실패: {liveError}
        </div>
      )}
      {(!isLive || liveData) && (
      <div style={{ display: "grid", gridTemplateColumns: "320px 1fr", gap: 24 }} className="dash-grid">
        {/* Left: gallery */}
        <div>
          <div style={{ position: "relative" }}>
            {cur.representativeImageUrl ? (
              <img src={cur.representativeImageUrl} alt={cur.name}
                   style={{ width: 320, height: 320, objectFit: "cover", borderRadius: 10, background: "var(--bg-elev)" }} />
            ) : (
              <ProductThumb tone={product.tone} name={cur.name} size={320} radius={10} />
            )}
            <span style={{ position: "absolute", top: 12, left: 12 }}>
              <StatusBadge status={product.status} />
            </span>
          </div>
          {isLive && cur.optionalImages.length > 0 && (
            <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 6, marginTop: 8 }}>
              {cur.optionalImages.slice(0, 4).map((img, i) => (
                <img key={i} src={img.url} alt=""
                     style={{ width: "100%", height: 72, objectFit: "cover", borderRadius: 6, background: "var(--bg-elev)" }} />
              ))}
            </div>
          )}
          <div className="card" style={{ marginTop: 16 }}>
            <div className="card-body" style={{ padding: 14 }}>
              <div className="text-xs muted">최종가 (할인 적용)</div>
              <div style={{ fontSize: 22, fontWeight: 700, marginTop: 2, color: "var(--accent)" }} className="tabular">
                {formatKRW(currentDiscountedPrice)}
              </div>
              <div className="text-xs muted" style={{ marginTop: 4 }}>
                판매가 <strong className="tabular" style={{ color: "var(--text)" }}>{formatKRW(get("salePrice"))}</strong>
                {get("immediateDiscount") > 0 && (
                  <> · 즉시할인 <strong style={{ color: "var(--danger)" }}>-{formatNum(get("immediateDiscount"))}원</strong></>
                )}
              </div>
              <div className="divider" style={{ margin: "12px 0" }} />
              <div className="row gap-3" style={{ alignItems: "flex-start" }}>
                <div style={{ flex: 1 }}>
                  <div className="text-xs muted">재고</div>
                  <div style={{ marginTop: 2, fontWeight: 600 }} className="tabular">
                    {formatNum(get("stockQuantity"))}
                    {isDirty("stockQuantity") && <span className="text-xs muted" style={{ marginLeft: 4 }}>(미적용)</span>}
                  </div>
                </div>
                {!isLive && (
                  <div style={{ flex: 1 }}>
                    <div className="text-xs muted">평점</div>
                    <div className="row gap-2" style={{ marginTop: 2 }}>
                      <window.I.Star size={14} fill="#f59e0b" stroke="#f59e0b" />
                      <strong>{product.rating}</strong>
                      <span className="text-xs muted">({formatNum(product.reviews)})</span>
                    </div>
                  </div>
                )}
              </div>
            </div>
          </div>
        </div>

        {/* Right: details */}
        <div>
          <div className="row gap-2" style={{ marginBottom: 12, fontSize: 12 }}>
            <span className="badge" title={cur.wholeCategoryName}>
              {cat?.icon} {cur.wholeCategoryName || cat?.name || "(카테고리 없음)"}
            </span>
            {isLive && cur.leafCategoryId && (
              <span className="badge muted">카테고리 ID: {cur.leafCategoryId}</span>
            )}
          </div>

          <div className="seg" style={{ marginBottom: 16 }}>
            {[
              ["overview", "기본정보"],
              ["pricing", "가격/재고"],
              ["desc", "상세설명"],
              ["sales", "판매통계"],
            ].map(([k, l]) => (
              <button key={k} className={"seg-btn " + (tab === k ? "active" : "")} onClick={() => setTab(k)}>{l}</button>
            ))}
          </div>

          {tab === "overview" && (
            <div className="flex-col gap-4">
              <Field label={"상품명" + (isDirty("name") ? " (변경됨)" : "")}>
                <input className={"input " + (isDirty("name") ? "dirty" : "")}
                       value={get("name")}
                       onChange={e => setEdit("name", e.target.value)} />
              </Field>
              <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
                <Field label="카테고리">
                  {isLive ? (
                    <input className="input" value={cur.wholeCategoryName} readOnly title="카테고리 변경은 별도 작업 필요" />
                  ) : (
                    <select className="select" value={get("name") && product.category} onChange={e => {/* readonly in live */}}>
                      {window.MOCK.CATEGORIES.map(c => <option key={c.id} value={c.id}>{c.name}</option>)}
                    </select>
                  )}
                </Field>
                <Field label={isLive ? "channelProductNo" : "브랜드"}>
                  <input className="input font-mono" value={isLive ? (product.channelProductNo || "") : product.brand} readOnly />
                </Field>
              </div>
              <Field label={isLive ? "originProductNo" : "SKU"}>
                <input className="input font-mono" value={isLive ? product.originProductNo : product.sku} readOnly />
              </Field>
              <Field label="상품 상태">
                <div className="seg">
                  <button className={"seg-btn " + (cur.statusType === "SALE" ? "active" : "")} disabled>판매중 (SALE)</button>
                  <button className={"seg-btn " + (cur.statusType === "OUTOFSTOCK" ? "active" : "")} disabled>품절</button>
                  <button className={"seg-btn " + (cur.statusType === "SUSPENSION" ? "active" : "")} disabled>판매중지</button>
                </div>
                {isLive && <div className="text-xs muted" style={{ marginTop: 4 }}>상태 변경은 향후 별도 작업으로</div>}
              </Field>
            </div>
          )}

          {tab === "pricing" && (
            <div className="flex-col gap-4">
              <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 12 }}>
                <Field label={"판매가 (₩)" + (isDirty("salePrice") ? " · 변경" : "")}>
                  <input className={"input tabular " + (isDirty("salePrice") ? "dirty" : "")}
                         type="text" value={formatNum(get("salePrice"))}
                         onChange={e => setEdit("salePrice", parseInt(e.target.value.replace(/[^0-9]/g, "")) || 0)} />
                </Field>
                <Field label={"즉시할인 (₩)" + (isDirty("immediateDiscount") ? " · 변경" : "")}>
                  <input className={"input tabular " + (isDirty("immediateDiscount") ? "dirty" : "")}
                         type="text" value={formatNum(get("immediateDiscount"))}
                         onChange={e => setEdit("immediateDiscount", parseInt(e.target.value.replace(/[^0-9]/g, "")) || 0)} />
                </Field>
                <Field label="최종가 (자동)">
                  <input className="input tabular" value={formatNum(currentDiscountedPrice)} readOnly
                         style={{ background: "var(--accent-soft)", fontWeight: 600 }} />
                </Field>
              </div>
              <div className="card" style={{ background: "var(--bg-elev)" }}>
                <div className="card-body" style={{ padding: 14 }}>
                  <div className="row" style={{ justifyContent: "space-between" }}>
                    <span className="text-sm muted">실판매가 (고객 노출)</span>
                    <strong className="tabular" style={{ color: "var(--accent)" }}>{formatKRW(currentDiscountedPrice)}</strong>
                  </div>
                  {!isLive && margin !== null && (
                    <div className="row" style={{ justifyContent: "space-between", marginTop: 6 }}>
                      <span className="text-sm muted">개당 마진</span>
                      <strong className="tabular">{formatKRW(product.price - product.costPrice)} ({margin}%)</strong>
                    </div>
                  )}
                </div>
              </div>
              <Field label={"재고 수량" + (isDirty("stockQuantity") ? " · 변경" : "")}>
                <input className={"input tabular " + (isDirty("stockQuantity") ? "dirty" : "")}
                       type="number" value={get("stockQuantity")}
                       onChange={e => setEdit("stockQuantity", parseInt(e.target.value) || 0)} />
              </Field>
            </div>
          )}

          {tab === "desc" && (
            <Field label={"상품 상세 설명" + (isDirty("detailContent") ? " · 변경됨" : "")}>
              {isLive ? (
                <>
                  <div className="text-xs muted" style={{ marginBottom: 8 }}>
                    블록 에디터 — 이미지를 추가/삭제/순서변경하고 텍스트와 섞을 수 있습니다.
                    저장 버튼을 누르면 네이버 SmartEditor 형식으로 변환되어 적용됩니다.
                  </div>
                  <window.DetailEditor
                    initialHtml={cur.detailContent}
                    isvmCode={product.sku || product.productCode || ""}
                    onChange={(html) => {
                      // 원본과 동일하면 dirty 표시 제거 (불필요한 PUT 방지)
                      if (html === cur.detailContent) {
                        setEdits(prev => {
                          if (prev.detailContent === undefined) return prev;
                          const { detailContent: _omit, ...rest } = prev;
                          return rest;
                        });
                      } else {
                        setEdit("detailContent", html);
                      }
                    }}
                  />
                </>
              ) : (
                <textarea className="input textarea" rows={10}
                          value={get("detailContent")}
                          onChange={e => setEdit("detailContent", e.target.value)} />
              )}
            </Field>
          )}

          {tab === "sales" && (
            <div className="flex-col gap-4">
              {isLive ? (
                <div className="card">
                  <div className="card-body" style={{ padding: 20, textAlign: "center", color: "var(--text-muted)" }}>
                    <window.I.AlertCircle size={32} stroke="var(--text-subtle)" style={{ marginBottom: 8 }} />
                    <div className="text-sm">판매 통계는 별도 API 연동 필요</div>
                    <div className="text-xs muted" style={{ marginTop: 4 }}>
                      현재는 상품 조회 API만 연동됨. 향후 주문 통계 endpoint 연동 시 표시됩니다.
                    </div>
                  </div>
                </div>
              ) : (
                <>
                  <div className="stat-grid" style={{ gridTemplateColumns: "1fr 1fr 1fr" }}>
                    <div className="stat-tile">
                      <div className="stat-label">30일 판매량</div>
                      <div className="stat-value">{product.sales30d}<span style={{ fontSize: 14, fontWeight: 500, marginLeft: 4 }}>건</span></div>
                    </div>
                    <div className="stat-tile">
                      <div className="stat-label">30일 매출</div>
                      <div className="stat-value" style={{ fontSize: 18 }}>{formatKRW(product.price * product.sales30d)}</div>
                    </div>
                    <div className="stat-tile">
                      <div className="stat-label">전환율</div>
                      <div className="stat-value">{(product.sales30d / product.views30d * 100).toFixed(1)}<span style={{ fontSize: 14, fontWeight: 500 }}>%</span></div>
                    </div>
                  </div>
                  <div className="card">
                    <div className="card-header"><div className="card-title">최근 14일 판매 추이</div></div>
                    <div className="card-body" style={{ padding: 16 }}>
                      <MiniSpark data={Array.from({ length: 14 }, () => Math.round(product.sales30d / 30 * (0.7 + Math.random() * 0.6)))} height={80} />
                    </div>
                  </div>
                </>
              )}
            </div>
          )}
        </div>
      </div>
      )}
    </Modal>
  );
}

function Field({ label, children }) {
  return (
    <div>
      <div className="text-xs muted" style={{ marginBottom: 6, fontWeight: 500 }}>{label}</div>
      {children}
    </div>
  );
}

window.ProductDetail = ProductDetail;
