// === ISVM 검색 → 네이버 등록 (real API) ===
const { useState: useStateIS, useMemo: useMemoIS, useEffect: useEffectIS } = React;

// 네이버 검색/등록에 방해되는 특수문자 정제.
// 네이버가 명시한 상품명 등록불가 문자: \ * ? " < >
//   - *  → x (사용자 요청 — 곱하기 기호 의도)
//   - 나머지 → 제거
function cleanProductName(name) {
  if (!name) return name;
  return name
    .replace(/\*/g, "x")                                // 별표 → 곱하기 x
    .replace(/[\\?"<>]/g, "")                            // 네이버 차단 문자 제거
    .replace(/[★☆♥♡◆◇▶◀▲▼●○■□◈◉◐◑▣▤▥▦▧▨▩※♠♣♣♤♧]/g, "")   // 장식 기호 제거
    .replace(/[【】〔〕〈〉《》「」『』]/g, "")              // 장식 괄호 제거
    .replace(/\s{2,}/g, " ")                             // 다중 공백 정리
    .trim();
}

function ISVMScreen({ products, setProducts, goto }) {
  const [keyword, setKeyword] = useStateIS("");
  const [sort, setSort] = useStateIS("sales");
  const [limit, setLimit] = useStateIS(500);   // 한 번에 받을 최대 (ISVM은 limit만 받음, 페이지 미지원)
  const [results, setResults] = useStateIS([]);
  const [loading, setLoading] = useStateIS(false);
  const [error, setError] = useStateIS("");
  const [health, setHealth] = useStateIS(null);
  const [selected, setSelected] = useStateIS(new Set());
  const [registerForm, setRegisterForm] = useStateIS(null);
  const [naverPreview, setNaverPreview] = useStateIS(null);
  const [registered, setRegistered] = useStateIS(new Set());
  const [creds, setCreds] = useStateIS(window.API.loadCreds());
  // 클라이언트 측 페이지네이션 — 4 컬럼 × 8 행 = 32개/페이지
  const PAGE_SIZE = 32;
  const [page, setPage] = useStateIS(1);
  const totalPages = Math.max(1, Math.ceil(results.length / PAGE_SIZE));
  const currentPage = Math.min(page, totalPages);
  const pageStart = (currentPage - 1) * PAGE_SIZE;
  const pagedResults = results.slice(pageStart, pageStart + PAGE_SIZE);

  useEffectIS(() => {
    window.API.isvmHealth().then(setHealth);
  }, []);

  const doSearch = async () => {
    if (!keyword.trim()) { window.toast("검색어를 입력하세요"); return; }
    setLoading(true); setError(""); setResults([]); setSelected(new Set()); setPage(1);
    try {
      const data = await window.API.isvmSearch({ keyword: keyword.trim(), limit: parseInt(limit) || 500, sort });
      // 네이버 등록/검색 방해 특수문자 정제
      const cleaned = data.map(item => ({ ...item, name: cleanProductName(item.name) }));
      setResults(cleaned);
      window.toast(`${cleaned.length}개 상품 검색 완료`);
    } catch (e) {
      const isCors = String(e.message || e).includes("Failed to fetch") || String(e.message || e).includes("NetworkError");
      setError(isCors
        ? "ISVM 서버에 직접 연결할 수 없습니다 (CORS). 데모용 샘플 데이터를 표시합니다."
        : `검색 실패: ${e.message}`);
      // Fallback demo data so UI is testable from any origin
      setResults(generateDemoResults(keyword.trim()));
    } finally {
      setLoading(false);
    }
  };

  const toggleOne = (code) => {
    const s = new Set(selected);
    s.has(code) ? s.delete(code) : s.add(code);
    setSelected(s);
  };

  const isLive = window.API.naverConfigured();
  // 라이브 모드 등록 상태
  const [templateProductId, setTemplateProductId] = useStateIS("");
  const [registering, setRegistering] = useStateIS(false);
  const [registerResult, setRegisterResult] = useStateIS(null);
  // 상세설명 모드
  const [detailMode, setDetailMode] = useStateIS("auto"); // "auto" | "manual"
  // 수동 모드용: 이미지 목록 (ISVM + PC 업로드 합쳐서 관리)
  // 각 항목: { id, source:'isvm'|'pc', url?:string, file?:File, kind?:string, selected:boolean }
  const [detailImages, setDetailImages] = useStateIS([]);
  const [loadingIsvmImages, setLoadingIsvmImages] = useStateIS(false);
  const [uploadProgress, setUploadProgress] = useStateIS(null); // { done, total, label }

  const openRegister = (item) => {
    setRegisterResult(null);
    setDetailMode("auto");
    setDetailImages([]);
    setUploadProgress(null);
    // template 자동 선택 — 가장 최근 활성 상품 (있으면)
    const firstLiveProduct = products.find(p => p.originProductNo);
    setTemplateProductId(firstLiveProduct?.originProductNo ? String(firstLiveProduct.originProductNo) : "");
    setRegisterForm({
      product_code: item.product_code,
      name: item.name,
      brand: item.brand || "",
      purchase_price: item.purchase_price,
      // 권장 마진 60%
      sale_price: Math.round((item.purchase_price * 1.6) / 10) * 10,
      image_url: item.image_url,
      stock: 50,
      desc: `${item.name}\n\n공급사: ${item.brand || "-"} · ISVM 코드: ${item.product_code}`,
      leafCategoryId: firstLiveProduct?.naverCategoryId || "50000000",
      baseFee: 3000,
    });
    // 라이브 모드면 ISVM 다중 이미지 사전 로드 (수동 모드 진입 대비)
    if (isLive && item.product_code) {
      setLoadingIsvmImages(true);
      window.API.isvmFetchProductImages(item.product_code)
        .then(imgs => {
          const list = imgs.map((img, i) => ({
            id: 'isvm-' + i,
            source: 'isvm',
            url: img.url,
            kind: img.kind,
            selected: true,
          }));
          setDetailImages(list);
        })
        .catch(err => console.warn("[ISVM 이미지 로드 실패]", err.message))
        .finally(() => setLoadingIsvmImages(false));
    }
  };

  // 이미지 그리드 조작
  const toggleDetailImage = (id) => {
    setDetailImages(prev => prev.map(it => it.id === id ? { ...it, selected: !it.selected } : it));
  };
  const moveDetailImage = (id, direction) => {
    setDetailImages(prev => {
      const idx = prev.findIndex(it => it.id === id);
      if (idx < 0) return prev;
      const newIdx = direction === 'up' ? idx - 1 : idx + 1;
      if (newIdx < 0 || newIdx >= prev.length) return prev;
      const next = [...prev];
      [next[idx], next[newIdx]] = [next[newIdx], next[idx]];
      return next;
    });
  };
  const removeDetailImage = (id) => {
    setDetailImages(prev => prev.filter(it => it.id !== id));
  };
  const addPcFiles = (files) => {
    const additions = Array.from(files).map((f, i) => ({
      id: 'pc-' + Date.now() + '-' + i,
      source: 'pc',
      file: f,
      url: URL.createObjectURL(f),  // 미리보기용 blob URL
      kind: 'pc',
      selected: true,
    }));
    setDetailImages(prev => [...prev, ...additions]);
  };

  const previewNaverPayload = async () => {
    if (!isLive) {
      // mock 모드: 구버전 빌더로 추측 페이로드
      const p = window.API.buildNaverProductPayload({
        product_code: registerForm.product_code,
        name: registerForm.name,
        brand: registerForm.brand,
        desc: registerForm.desc,
        image_url: registerForm.image_url,
        salePrice: parseInt(registerForm.sale_price) || 0,
        stock: parseInt(registerForm.stock) || 0,
      }, {
        leafCategoryId: registerForm.leafCategoryId,
        baseFee: parseInt(registerForm.baseFee) || 3000,
      });
      setNaverPreview(p);
      return;
    }
    // 라이브 모드: template 기반 (자동 선택 — 매장의 첫 라이브 상품 사용)
    if (!templateProductId) { window.toast("매장에 라이브 상품이 1개 이상 있어야 등록 가능"); return; }
    try {
      const tpl = await window.API.naverFetchOriginProduct(parseInt(templateProductId));
      const payload = JSON.parse(JSON.stringify(tpl));
      delete payload.originProductNo;
      delete payload.smartstoreChannelProductNo;
      payload.originProduct.name = registerForm.name;
      payload.originProduct.salePrice = parseInt(registerForm.sale_price) || 0;
      payload.originProduct.stockQuantity = parseInt(registerForm.stock) || 0;
      payload.originProduct.leafCategoryId = registerForm.leafCategoryId;
      if (registerForm.image_url) {
        payload.originProduct.images = {
          representativeImage: { url: registerForm.image_url },
          optionalImages: [],
        };
      }
      payload.originProduct.detailContent = `<div>${(registerForm.desc || registerForm.name).replace(/[<>]/g, "")}</div>`;
      payload.originProduct.detailAttribute = payload.originProduct.detailAttribute || {};
      payload.originProduct.detailAttribute.sellerCodeInfo = payload.originProduct.detailAttribute.sellerCodeInfo || {};
      payload.originProduct.detailAttribute.sellerCodeInfo.sellerManagementCode = registerForm.product_code;
      if (payload.originProduct.customerBenefit?.immediateDiscountPolicy) {
        delete payload.originProduct.customerBenefit.immediateDiscountPolicy;
      }
      if (payload.smartstoreChannelProduct) {
        payload.smartstoreChannelProduct.channelProductName = registerForm.name;
      }
      setNaverPreview(payload);
    } catch (err) {
      window.toast("미리보기 실패: " + err.message);
    }
  };

  const submitRegister = async () => {
    if (!isLive) {
      // mock 모드: 시뮬레이션
      const newId = "P" + (10300 + products.length);
      const newProduct = {
        id: newId, name: registerForm.name, category: "fashion",
        price: parseInt(registerForm.sale_price) || 0,
        costPrice: parseInt(registerForm.purchase_price) || 0,
        stock: parseInt(registerForm.stock) || 0,
        sales30d: 0, rating: 0, reviews: 0, status: "active", views30d: 0,
        sku: registerForm.product_code, brand: registerForm.brand || "ISVM",
        tone: parseInt(registerForm.product_code, 10) % 9 || 0,
        desc: registerForm.desc, image_url: registerForm.image_url,
      };
      setProducts(prev => [...prev, newProduct]);
      setRegistered(prev => new Set(prev).add(registerForm.product_code));
      setRegisterForm(null); setNaverPreview(null);
      window.toast(`'${newProduct.name.slice(0, 24)}…' 등록 (시뮬레이션)`);
      return;
    }
    // 라이브 모드: 실제 POST
    if (!templateProductId) {
      window.toast("매장에 라이브 상품이 1개 이상 있어야 등록 가능 (카테고리 참조용)");
      return;
    }
    setRegistering(true);
    setRegisterResult(null);
    try {
      // 1) 사용할 이미지 결정 (자동: 모든 ISVM, 수동: 선택된 것만 순서대로)
      let sourceImages = [];
      if (detailMode === "auto") {
        // 자동 — 미리 로드한 detailImages 전체 사용 (혹시 비어있으면 다시 조회)
        if (detailImages.length === 0) {
          try {
            const imgs = await window.API.isvmFetchProductImages(registerForm.product_code);
            sourceImages = imgs.map(img => ({ source: 'isvm', url: img.url }));
          } catch (err) { console.warn("[ISVM 이미지 재조회 실패]", err.message); }
        } else {
          sourceImages = detailImages.map(it => ({ source: it.source, url: it.url, file: it.file }));
        }
      } else {
        // 수동 — 선택된 것만, 그리드 순서대로
        sourceImages = detailImages.filter(it => it.selected).map(it => ({ source: it.source, url: it.url, file: it.file }));
      }

      // 메인 이미지 URL을 첫 번째로 강제 (대표 이미지가 representativeImage에 들어가도록)
      if (registerForm.image_url) {
        const mainIdx = sourceImages.findIndex(s => s.url === registerForm.image_url);
        if (mainIdx > 0) {
          const [main] = sourceImages.splice(mainIdx, 1);
          sourceImages.unshift(main);
        } else if (mainIdx < 0) {
          sourceImages.unshift({ source: 'isvm', url: registerForm.image_url });
        }
      }

      if (sourceImages.length === 0) {
        window.toast("등록할 이미지가 없습니다 (수동 모드면 1장 이상 선택 필요)");
        setRegistering(false);
        return;
      }

      // 2) 순차 업로드 — 진행 표시
      const uploadedUrls = [];
      setUploadProgress({ done: 0, total: sourceImages.length, label: "이미지 업로드 중" });
      for (let i = 0; i < sourceImages.length; i++) {
        const src = sourceImages[i];
        try {
          let naverUrl;
          if (src.source === 'pc' && src.file) {
            naverUrl = await window.API.naverUploadImageFile(src.file);
          } else if (src.url) {
            // 이미 네이버 URL이면 그대로 사용
            if (/(shop-phinf\.pstatic\.net|phinf\.pstatic\.net|naver\.com)/.test(src.url)) {
              naverUrl = src.url;
            } else {
              naverUrl = await window.API.naverUploadImageFromUrl(src.url);
            }
          }
          if (naverUrl) uploadedUrls.push(naverUrl);
        } catch (err) {
          console.warn("[이미지 " + (i + 1) + "/" + sourceImages.length + " 업로드 실패]", err.message);
        }
        setUploadProgress({ done: i + 1, total: sourceImages.length, label: "이미지 업로드 중" });
      }

      if (uploadedUrls.length === 0) {
        throw new Error("모든 이미지 업로드 실패");
      }

      // 3) detailContent SmartEditor HTML 생성 (모든 업로드된 이미지)
      const detailHtml = window.API.buildSmartEditorImagesHtml(uploadedUrls);

      // 4) 등록 호출 (representativeImage = 첫 URL, optionalImages는 자동으로 다음 9장)
      setUploadProgress({ done: 0, total: 1, label: "네이버에 등록 중" });
      const overrides = {
        // 등록 직전 한번 더 sanitize — 사용자가 폼에서 직접 수정 시 * 들어갈 수 있음
        name: cleanProductName(registerForm.name),
        salePrice: parseInt(registerForm.sale_price) || 0,
        stockQuantity: parseInt(registerForm.stock) || 0,
        leafCategoryId: registerForm.leafCategoryId,
        imageUrl: uploadedUrls[0],
        optionalImageUrls: uploadedUrls.slice(1, 10),  // 최대 9장
        detailContent: detailHtml,
        sellerCode: registerForm.product_code,
      };
      const result = await window.API.naverRegisterFromTemplate(parseInt(templateProductId), overrides);
      setUploadProgress(null);
      setRegisterResult({ ok: true, response: result });
      setRegistered(prev => new Set(prev).add(registerForm.product_code));
      window.toast(`'${registerForm.name.slice(0, 24)}…' 네이버에 등록되었습니다`);
    } catch (err) {
      console.error("[ISVM register]", err);
      setRegisterResult({ ok: false, error: err.message });
      window.toast("등록 실패: " + err.message);
    } finally {
      setRegistering(false);
    }
  };

  const corsWarning = error && error.includes("CORS");

  return (
    <div className="page">
      <div className="page-header" style={{ display: "flex", alignItems: "flex-end", gap: 16 }}>
        <div style={{ flex: 1 }}>
          <h1 className="page-title">ISVM → 네이버 스마트스토어 연동</h1>
          <p className="page-desc">ISVM 도매 사이트에서 상품을 검색하고 네이버 스마트스토어에 등록합니다</p>
        </div>
        <button className="btn" onClick={() => goto("settings")}>
          <window.I.Settings size={14} /> API 설정
        </button>
      </div>

      {/* Connection bar */}
      <div className="card" style={{ marginBottom: 12 }}>
        <div className="card-body" style={{ padding: 14, display: "flex", alignItems: "center", gap: 16, flexWrap: "wrap" }}>
          <div className="row gap-3">
            <div style={{ width: 36, height: 36, borderRadius: 8, background: "linear-gradient(135deg, #6366f1, #8b5cf6)", color: "white", display: "flex", alignItems: "center", justifyContent: "center", fontWeight: 700 }}>IS</div>
            <div>
              <div style={{ fontWeight: 600, fontSize: 13 }}>ISVM Crawler API</div>
              <div className="text-xs muted">{window.API.ISVM_BASE}</div>
            </div>
            <span className={"badge badge-dot " + (health === true ? "badge-success" : health === false ? "badge-danger" : "")}>
              {health === true ? "연결됨" : health === false ? "연결 실패" : "확인 중..."}
            </span>
          </div>
          <window.I.ChevronRight size={20} className="muted" />
          <div className="row gap-3">
            <div style={{ width: 36, height: 36, borderRadius: 8, background: "var(--accent)", color: "white", display: "flex", alignItems: "center", justifyContent: "center", fontWeight: 800 }}>N</div>
            <div>
              <div style={{ fontWeight: 600, fontSize: 13 }}>네이버 커머스 API</div>
              <div className="text-xs muted">
                {creds.naver_client_id
                  ? `client_id: ${creds.naver_client_id.slice(0, 6)}••••••`
                  : "자격증명 미설정"}
              </div>
            </div>
            <span className={"badge badge-dot " + (creds.naver_client_id && creds.proxy_url ? "badge-success" : "badge-warn")}>
              {creds.naver_client_id && creds.proxy_url ? "프록시 연결" : "프록시 필요"}
            </span>
          </div>
        </div>
      </div>

      {/* Search bar */}
      <div className="toolbar">
        <div className="input-with-icon" style={{ flex: 1, maxWidth: 480 }}>
          <window.I.Search size={14} className="input-icon" />
          <input className="input" placeholder="ISVM 키워드 검색 (예: 동관터미널, 티셔츠)..."
                 value={keyword} onChange={e => setKeyword(e.target.value)}
                 onKeyDown={e => e.key === "Enter" && doSearch()} />
        </div>
        <div className="seg">
          <button className={"seg-btn " + (sort === "sales" ? "active" : "")} onClick={() => setSort("sales")}>판매량순</button>
          <button className={"seg-btn " + (sort === "relevance" ? "active" : "")} onClick={() => setSort("relevance")}>관련도순</button>
        </div>
        <select className="select" style={{ width: 110 }} value={limit} onChange={e => setLimit(parseInt(e.target.value))}
                title="ISVM에서 한 번에 받을 최대 개수 (페이지네이션은 클라이언트에서 자동)">
          {[50, 100, 200, 500, 1000].map(n => <option key={n} value={n}>최대 {n}개</option>)}
        </select>
        <button className="btn btn-primary" onClick={doSearch} disabled={loading}>
          {loading ? "검색 중..." : <><window.I.Search size={14} /> 검색</>}
        </button>
      </div>

      {error && (
        <div style={{ padding: "10px 14px", borderRadius: 8, marginBottom: 12,
                      background: corsWarning ? "rgba(245, 158, 11, 0.1)" : "var(--danger-soft)",
                      border: `1px solid ${corsWarning ? "var(--warning)" : "var(--danger)"}`,
                      fontSize: 13 }}>
          <strong>{corsWarning ? "⚠️ CORS 차단" : "❌ 오류"}:</strong> {error}
          {corsWarning && (
            <div className="text-xs muted" style={{ marginTop: 4 }}>
              ISVM 서버에 이 도메인을 화이트리스트에 등록하거나, 자체 백엔드를 통해 프록시하세요.
            </div>
          )}
        </div>
      )}

      {results.length === 0 && !loading && !error && (
        <div className="card">
          <div className="empty">
            <window.I.Search size={32} className="empty-icon" />
            <div style={{ marginBottom: 4 }}>키워드를 입력하고 검색하세요</div>
            <div className="text-sm">ISVM 도매 사이트의 실시간 매입가/이미지가 조회됩니다</div>
          </div>
        </div>
      )}

      {results.length > 0 && (
        <>
          <div className="row gap-2 muted" style={{ marginBottom: 8, fontSize: 12, alignItems: "center" }}>
            <span>검색 결과 {results.length}개</span>
            <span>·</span>
            <span>페이지 {currentPage}/{totalPages} · {pageStart + 1}~{Math.min(pageStart + PAGE_SIZE, results.length)} 표시</span>
            <span>·</span>
            <span>선택: {selected.size}</span>
            {selected.size > 0 && (
              <button className="btn btn-sm" onClick={() => setSelected(new Set())}>선택 해제</button>
            )}
            <div className="right row gap-2" style={{ alignItems: "center" }}>
              <button className="btn btn-sm" disabled={currentPage <= 1} onClick={() => setPage(currentPage - 1)}>
                <window.I.ChevronRight size={12} style={{ transform: "rotate(180deg)" }} /> 이전
              </button>
              <span style={{ minWidth: 60, textAlign: "center" }}><strong>{currentPage}</strong> / {totalPages}</span>
              <button className="btn btn-sm" disabled={currentPage >= totalPages} onClick={() => setPage(currentPage + 1)}>
                다음 <window.I.ChevronRight size={12} />
              </button>
            </div>
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(260px, 1fr))", gap: 12 }}>
            {pagedResults.map(item => {
              const isReg = registered.has(item.product_code) || products.some(p => p.sku === item.product_code);
              const margin = ((item.purchase_price * 1.6 - item.purchase_price) / (item.purchase_price * 1.6) * 100).toFixed(0);
              return (
                <div key={item.product_code} className="card" style={{ display: "flex", flexDirection: "column" }}>
                  <div style={{ position: "relative", aspectRatio: "1", background: "var(--bg-elev)" }}>
                    {item.image_url
                      ? <img src={item.image_url} alt="" style={{ width: "100%", height: "100%", objectFit: "cover" }}
                             onError={e => { e.target.style.display = "none"; }} />
                      : <ProductThumb tone={parseInt(item.product_code) % 9} name={item.name} size="100%" radius={0} />}
                    <span style={{ position: "absolute", top: 8, left: 8, background: "rgba(0,0,0,0.7)", color: "white", fontSize: 10, padding: "2px 6px", borderRadius: 4, fontFamily: "monospace" }}>
                      {item.product_code}
                    </span>
                    {isReg && (
                      <span style={{ position: "absolute", top: 8, right: 8 }} className="badge badge-success">
                        <window.I.Check size={11} /> 등록됨
                      </span>
                    )}
                  </div>
                  <div style={{ padding: 12, flex: 1, display: "flex", flexDirection: "column" }}>
                    <div style={{ fontSize: 13, fontWeight: 500, lineHeight: 1.4, marginBottom: 4 }}>{item.name}</div>
                    <div className="text-xs muted" style={{ marginBottom: 8 }}>{item.brand || "-"}</div>
                    <div style={{ flex: 1 }} />
                    <div className="row" style={{ justifyContent: "space-between", marginBottom: 8 }}>
                      <div>
                        <div className="text-xs muted">매입가</div>
                        <div className="tabular" style={{ fontWeight: 600 }}>{formatKRW(item.purchase_price)}</div>
                      </div>
                      <div style={{ textAlign: "right" }}>
                        <div className="text-xs muted">권장 판매가 (마진 {margin}%)</div>
                        <div className="tabular text-sm" style={{ color: "var(--accent)" }}>
                          {formatKRW(Math.round(item.purchase_price * 1.6 / 10) * 10)}
                        </div>
                      </div>
                    </div>
                    <button className={"btn " + (isReg ? "" : "btn-primary")} disabled={isReg} onClick={() => openRegister(item)}>
                      {isReg ? <><window.I.Check size={14} /> 이미 등록됨</> : <><window.I.Plus size={14} /> 네이버 등록</>}
                    </button>
                  </div>
                </div>
              );
            })}
          </div>
        </>
      )}

      {/* Register modal */}
      {registerForm && (
        <Modal open={true} onClose={() => { if (!registering) { setRegisterForm(null); setNaverPreview(null); setRegisterResult(null); } }} size="lg" title="네이버 스마트스토어 상품 등록"
               footer={
                 registerResult?.ok ? (
                   <button className="btn btn-primary" onClick={() => { setRegisterForm(null); setNaverPreview(null); setRegisterResult(null); }}>닫기</button>
                 ) : (
                   <>
                     <button className="btn btn-ghost" onClick={previewNaverPayload} disabled={registering}>
                       <window.I.Eye size={14} /> API 페이로드 미리보기
                     </button>
                     <div className="right" />
                     <button className="btn" onClick={() => { setRegisterForm(null); setNaverPreview(null); setRegisterResult(null); }} disabled={registering}>취소</button>
                     <button className="btn btn-primary" onClick={submitRegister} disabled={registering}>
                       <window.I.Check size={14} /> {registering ? "등록 중..." : isLive ? "네이버에 등록" : "등록 (시뮬레이션)"}
                     </button>
                   </>
                 )
               }>
          <div style={{ display: "grid", gridTemplateColumns: "240px 1fr", gap: 24 }}>
            <div>
              {registerForm.image_url
                ? <img src={registerForm.image_url} alt="" style={{ width: 240, height: 240, objectFit: "cover", borderRadius: 10, background: "var(--bg-elev)" }} />
                : <ProductThumb tone={parseInt(registerForm.product_code) % 9} name={registerForm.name} size={240} radius={10} />}
              <div className="card" style={{ marginTop: 12, background: "var(--bg-elev)" }}>
                <div className="card-body" style={{ padding: 12 }}>
                  <div className="text-xs muted" style={{ marginBottom: 4 }}>ISVM 출처</div>
                  <div className="font-mono text-sm" style={{ fontWeight: 600 }}>{registerForm.product_code}</div>
                  <div className="text-xs muted" style={{ marginTop: 6 }}>매입가 {formatKRW(registerForm.purchase_price)}</div>
                </div>
              </div>
            </div>
            <div className="flex-col gap-3">
              <Field label="상품명">
                <input className="input" value={registerForm.name} onChange={e => setRegisterForm({ ...registerForm, name: e.target.value })} />
              </Field>
              <Field label="브랜드">
                <input className="input" value={registerForm.brand} onChange={e => setRegisterForm({ ...registerForm, brand: e.target.value })} />
              </Field>
              <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
                <Field label="판매가 (₩)">
                  <input className="input tabular" value={formatNum(registerForm.sale_price)}
                         onChange={e => setRegisterForm({ ...registerForm, sale_price: parseInt(e.target.value.replace(/[^0-9]/g, "")) || 0 })} />
                </Field>
                <Field label="초기 재고">
                  <input className="input tabular" type="number" value={registerForm.stock}
                         onChange={e => setRegisterForm({ ...registerForm, stock: parseInt(e.target.value) || 0 })} />
                </Field>
              </div>
              <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
                <Field label="네이버 카테고리 ID (leafCategoryId)">
                  <input className="input font-mono" value={registerForm.leafCategoryId}
                         onChange={e => setRegisterForm({ ...registerForm, leafCategoryId: e.target.value })} />
                </Field>
                <Field label="기본 배송비 (₩)">
                  <input className="input tabular" type="number" value={registerForm.baseFee}
                         onChange={e => setRegisterForm({ ...registerForm, baseFee: parseInt(e.target.value) || 0 })} />
                </Field>
              </div>
              <Field label="상세 설명">
                <textarea className="input textarea" rows={4} value={registerForm.desc}
                          onChange={e => setRegisterForm({ ...registerForm, desc: e.target.value })} />
              </Field>
              <div style={{ background: "var(--accent-soft)", padding: "10px 12px", borderRadius: 6, fontSize: 12 }}>
                <strong>마진:</strong> {formatKRW(registerForm.sale_price - registerForm.purchase_price)} ({((registerForm.sale_price - registerForm.purchase_price) / registerForm.sale_price * 100).toFixed(1)}%)
              </div>
              {isLive && (
                <>
                  {templateProductId ? (
                    <div className="text-xs muted" style={{ padding: "8px 12px", background: "var(--bg-elev)", borderRadius: 6, border: "1px solid var(--border)" }}>
                      카테고리/원산지/인증은 매장의 기존 상품(#{templateProductId})에서 자동 참조 ·
                      배송/A&S는 설정값 사용 · 상세설명/SEO는 이 상품 정보 사용
                    </div>
                  ) : (
                    <div style={{ padding: "10px 12px", background: "rgba(239, 68, 68, 0.08)", border: "1px solid rgba(239, 68, 68, 0.35)", borderRadius: 6, fontSize: 12, color: "var(--danger)" }}>
                      <window.I.AlertCircle size={14} stroke="var(--danger)" style={{ verticalAlign: "middle", marginRight: 6 }} />
                      라이브 상품이 1개도 없어서 카테고리 참조 불가. 먼저 네이버에 상품 1개 이상 등록되어 있어야 합니다.
                    </div>
                  )}
                  <div style={{ padding: "10px 12px", background: "rgba(245, 158, 11, 0.08)", border: "1px solid rgba(245, 158, 11, 0.35)", borderRadius: 6, fontSize: 12, color: "var(--text-muted)" }}>
                    <window.I.AlertCircle size={14} stroke="var(--warning)" style={{ verticalAlign: "middle", marginRight: 6 }} />
                    <strong style={{ color: "var(--text)" }}>주의:</strong> 등록은 즉시 네이버 스토어에 반영됩니다.
                    이미지는 네이버가 자체 서버에 저장. 카테고리는 leafCategoryId 직접 입력 시 우선 적용.
                  </div>
                </>
              )}
            </div>
          </div>

          {/* 상세설명 모드 (라이브) */}
          {isLive && (
            <div className="card" style={{ marginTop: 16 }}>
              <div className="card-header">
                <div className="card-title">상세설명 이미지 ({detailMode === "auto" ? "자동" : "직접 선택"})</div>
                <div className="right seg">
                  <button className={"seg-btn " + (detailMode === "auto" ? "active" : "")} onClick={() => setDetailMode("auto")}>자동</button>
                  <button className={"seg-btn " + (detailMode === "manual" ? "active" : "")} onClick={() => setDetailMode("manual")}>직접 선택</button>
                </div>
              </div>
              <div className="card-body" style={{ padding: 14 }}>
                {detailMode === "auto" ? (
                  <div className="text-sm muted">
                    ISVM에서 가져온 모든 이미지({loadingIsvmImages ? "로딩 중..." : detailImages.length + "장"})를 자동으로 SmartEditor 형식 HTML로 변환해서 상세설명에 삽입합니다. 메인은 대표 이미지로, 처음 10장은 갤러리 슬라이더, 모두 상세 페이지에 표시.
                  </div>
                ) : (
                  <>
                    <div className="text-sm muted" style={{ marginBottom: 10 }}>
                      체크된 이미지가 상세설명에 표시됩니다. 순서는 ↑↓ 버튼으로 조정. PC에서 이미지 추가도 가능.
                    </div>
                    <div className="row gap-2" style={{ marginBottom: 10 }}>
                      <label className="btn btn-sm" style={{ cursor: "pointer" }}>
                        <window.I.Plus size={12} /> PC에서 이미지 추가
                        <input type="file" multiple accept="image/*" style={{ display: "none" }}
                               onChange={e => { addPcFiles(e.target.files); e.target.value = ""; }} />
                      </label>
                      <span className="text-xs muted" style={{ alignSelf: "center" }}>
                        선택: <strong>{detailImages.filter(i => i.selected).length}</strong> / 전체 {detailImages.length}장
                      </span>
                    </div>
                    {loadingIsvmImages && <div className="text-sm muted">ISVM 이미지 로딩 중...</div>}
                    <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(120px, 1fr))", gap: 8, maxHeight: 360, overflow: "auto", padding: 8, background: "var(--bg-elev)", borderRadius: 6 }}>
                      {detailImages.map((it, idx) => (
                        <div key={it.id} style={{
                          position: "relative", aspectRatio: "1", borderRadius: 6, overflow: "hidden",
                          border: it.selected ? "2px solid var(--accent)" : "2px solid var(--border)",
                          background: "white",
                        }}>
                          <img src={it.url} alt="" style={{ width: "100%", height: "100%", objectFit: "cover", cursor: "pointer", opacity: it.selected ? 1 : 0.4 }}
                               onClick={() => toggleDetailImage(it.id)}
                               onError={e => { e.target.style.background = '#fee'; e.target.alt = '로드 실패'; }} />
                          <div style={{ position: "absolute", top: 4, left: 4, background: "rgba(0,0,0,0.7)", color: "white", fontSize: 10, padding: "2px 5px", borderRadius: 3, fontWeight: 600 }}>
                            {idx + 1}
                          </div>
                          <div style={{ position: "absolute", top: 4, right: 4, background: it.source === "pc" ? "rgba(99, 102, 241, 0.9)" : "rgba(0,0,0,0.5)", color: "white", fontSize: 9, padding: "2px 4px", borderRadius: 3 }}>
                            {it.source === "pc" ? "PC" : "ISVM"}
                          </div>
                          <div style={{ position: "absolute", bottom: 0, left: 0, right: 0, display: "flex", gap: 2, padding: 4, background: "linear-gradient(to top, rgba(0,0,0,0.7), transparent)" }}>
                            <button className="btn btn-icon" style={{ padding: 2, minWidth: 0, width: 22, height: 22, background: "rgba(255,255,255,0.9)", color: "black" }} onClick={() => moveDetailImage(it.id, 'up')} disabled={idx === 0} title="앞으로">
                              <window.I.ArrowUp size={11} />
                            </button>
                            <button className="btn btn-icon" style={{ padding: 2, minWidth: 0, width: 22, height: 22, background: "rgba(255,255,255,0.9)", color: "black" }} onClick={() => moveDetailImage(it.id, 'down')} disabled={idx === detailImages.length - 1} title="뒤로">
                              <window.I.ArrowDown size={11} />
                            </button>
                            <div style={{ flex: 1 }} />
                            <button className="btn btn-icon" style={{ padding: 2, minWidth: 0, width: 22, height: 22, background: "rgba(239, 68, 68, 0.9)", color: "white" }} onClick={() => removeDetailImage(it.id)} title="제거">
                              <window.I.X size={11} />
                            </button>
                          </div>
                        </div>
                      ))}
                      {detailImages.length === 0 && !loadingIsvmImages && (
                        <div className="text-sm muted" style={{ gridColumn: "1 / -1", textAlign: "center", padding: 24 }}>
                          이미지가 없습니다. PC에서 추가하거나 자동 모드로 전환하세요.
                        </div>
                      )}
                    </div>
                  </>
                )}
              </div>
            </div>
          )}

          {/* 업로드 진행 상태 */}
          {uploadProgress && (
            <div style={{ marginTop: 12, padding: 12, borderRadius: 6, background: "var(--accent-soft)", border: "1px solid var(--accent)" }}>
              <div className="row" style={{ justifyContent: "space-between", marginBottom: 6, fontSize: 13 }}>
                <span><strong>{uploadProgress.label}</strong></span>
                <span>{uploadProgress.done} / {uploadProgress.total}</span>
              </div>
              <div style={{ height: 6, background: "var(--border)", borderRadius: 3, overflow: "hidden" }}>
                <div style={{ height: "100%", background: "var(--accent)", width: (uploadProgress.total ? uploadProgress.done / uploadProgress.total * 100 : 0) + "%", transition: "width 0.2s" }} />
              </div>
            </div>
          )}

          {registerResult && (
            <div style={{ marginTop: 16, padding: 12, borderRadius: 6, border: "1px solid " + (registerResult.ok ? "rgba(34,197,94,0.35)" : "rgba(239,68,68,0.35)"), background: registerResult.ok ? "rgba(34,197,94,0.08)" : "rgba(239,68,68,0.08)" }}>
              {registerResult.ok ? (
                <>
                  <div style={{ fontWeight: 600, marginBottom: 8, color: "var(--success)" }}>✓ 네이버 등록 완료</div>
                  <pre style={{ fontSize: 11, padding: 8, background: "var(--bg-elev)", borderRadius: 4, maxHeight: 200, overflow: "auto", margin: 0 }}>
                    {JSON.stringify(registerResult.response, null, 2)}
                  </pre>
                  <div className="text-xs muted" style={{ marginTop: 6 }}>
                    상품 관리 페이지에서 새로고침하면 새 상품이 보입니다.
                  </div>
                </>
              ) : (
                <>
                  <div style={{ fontWeight: 600, marginBottom: 6, color: "var(--danger)" }}>✗ 등록 실패</div>
                  <pre style={{ fontSize: 11, padding: 8, background: "var(--bg-elev)", borderRadius: 4, maxHeight: 200, overflow: "auto", margin: 0, whiteSpace: "pre-wrap" }}>
                    {registerResult.error}
                  </pre>
                  <div className="text-xs muted" style={{ marginTop: 6 }}>
                    네이버가 누락된 필수 필드를 알려주면 기준 상품을 다른 걸로 변경해보거나, leafCategoryId를 조정해보세요.
                  </div>
                </>
              )}
            </div>
          )}

          {naverPreview && (
            <div style={{ marginTop: 16 }}>
              <div className="text-xs muted" style={{ marginBottom: 6, fontWeight: 600 }}>POST {naverPreview && "https://api.commerce.naver.com/external/v1/products"}</div>
              <pre style={{ background: "var(--bg-elev)", border: "1px solid var(--border)", borderRadius: 8, padding: 12, fontSize: 11, maxHeight: 280, overflow: "auto", margin: 0 }}>
{JSON.stringify(naverPreview, null, 2)}
              </pre>
              <div className="text-xs muted" style={{ marginTop: 6 }}>
                ⚠️ 실제 등록은 서버 프록시(<code>{creds.proxy_url || "미설정"}</code>)를 통해 호출되어야 합니다.
                액세스 토큰은 서버에서 bcrypt 서명으로 발급받습니다.
              </div>
            </div>
          )}
        </Modal>
      )}
    </div>
  );
}

// Demo fallback (used when CORS blocks the real API in this preview)
function generateDemoResults(keyword) {
  const seed = (s) => { let h = 0; for (const c of s) h = (h * 31 + c.charCodeAt(0)) % 999983; return h; };
  return Array.from({ length: 8 }, (_, i) => {
    const code = String(seed(keyword + i) % 900000 + 100000);
    return {
      product_code: code,
      name: `${keyword} 관련 상품 ${i + 1} (데모)`,
      brand: ["경성", "대한", "한솔", "글로벌"][i % 4],
      purchase_price: Math.round((1000 + (seed(keyword + i) % 30000)) / 100) * 100,
      image_url: "",
    };
  });
}

window.ISVMScreen = ISVMScreen;
