// Detail modal — wired to /api/recent/detail/:keyword
const { useState: useState_M, useEffect: useEffect_M, useRef: useRef_M } = React;

function DetailModal({ kw, onClose }) {
  const [tab, setTab] = useState_M("overview");
  const [zoom, setZoom] = useState_M(null);
  const [toast, setToast] = useState_M(null);
  const [outcome, setOutcome] = useState_M(kw?.outcome || "");
  const [revenue, setRevenue] = useState_M(kw?.revenue || "");
  const [notes, setNotes] = useState_M(kw?.notes || "");
  const [detail, setDetail] = useState_M(null);
  const [loading, setLoading] = useState_M(true);
  const bodyRef = useRef_M(null);
  const notesTimer = useRef_M(null);

  if (!kw) return null;

  useEffect_M(() => {
    setLoading(true);
    AS_API.recentDetail(kw.kw)
      .then(d => { setDetail(d); setLoading(false); })
      .catch(() => setLoading(false));
  }, [kw.kw]);

  const cutImages = detail?.generatedImages;
  const cutUrls = cutImages?.urls || [];
  const cutTotal = 14;
  const cutDone = cutUrls.length;
  const cutBadge = cutDone > 0 ? `${cutDone}/${cutTotal}` : null;

  const tabs = [
    { id: "overview", lbl: "요약",      ico: "◎" },
    { id: "opus",     lbl: "Opus 분석", ico: "◇" },
    { id: "strategy", lbl: "판매 전략",  ico: "◈" },
    { id: "cuts",     lbl: "상세페이지 컷", ico: "▦", badge: cutBadge },
  ];

  useEffect_M(() => {
    const onKey = e => {
      if (e.key === "Escape") { if (zoom) setZoom(null); else onClose(); }
      else if (e.key === "ArrowLeft" && !e.target.matches("input,textarea,select")) {
        const i = tabs.findIndex(t => t.id === tab);
        if (i > 0) setTab(tabs[i - 1].id);
      } else if (e.key === "ArrowRight" && !e.target.matches("input,textarea,select")) {
        const i = tabs.findIndex(t => t.id === tab);
        if (i < tabs.length - 1) setTab(tabs[i + 1].id);
      } else if ((e.key === "j" || e.key === "k") && !e.target.matches("input,textarea,select")) {
        if (bodyRef.current) bodyRef.current.scrollBy({ top: e.key === "j" ? 200 : -200, behavior: "smooth" });
      }
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [tab, zoom]);

  const showToast = (msg, kind = "ok") => {
    setToast({ msg, kind });
    setTimeout(() => setToast(null), 2000);
  };

  const saveOutcome = async () => {
    try {
      await AS_API.updateOutcome(kw.kw, outcome, revenue ? +revenue : null);
      showToast("실전 결과 저장됨");
    } catch (e) { showToast("저장 실패: " + (e.error || e.message), "err"); }
  };

  const saveNotes = (val) => {
    setNotes(val);
    if (notesTimer.current) clearTimeout(notesTimer.current);
    notesTimer.current = setTimeout(() => {
      AS_API.updateGrade(kw.kw, { notes: val }).catch(() => {});
    }, 1000);
  };

  const copyTab = () => {
    navigator.clipboard?.writeText(`[${kw.kw}] ${kw.killer}`);
    showToast("클립보드 복사됨");
  };

  const stats = detail?.stats || {};
  const avgPrice = stats.avgPrice ? Math.round(stats.avgPrice).toLocaleString() + '원' : (kw.avgPrice ? Math.round(kw.avgPrice).toLocaleString() + '원' : '-');
  const avgReviews = stats.avgReviews ? Math.round(stats.avgReviews) + '건' : (kw.avgReviews ? Math.round(kw.avgReviews) + '건' : '-');
  const sellerRocket = kw.sellerRocketCount || stats.sellerRocketCount || 0;

  return (
    <div className="dm-bg" onClick={onClose}>
      <div className="dm" onClick={e => e.stopPropagation()} role="dialog" aria-modal="true">
        <header className="dm-head">
          <div className="dm-title-block">
            <div className="dm-crumb">
              <span>이력</span><span className="sep">›</span>
              <span>{kw.date}</span><span className="sep">›</span>
              <span className="curr">상세</span>
            </div>
            <div className="dm-title-row">
              <Grade g={kw.grade} size="lg"/>
              <h2 className="dm-title">{kw.kw}</h2>
              <span className="dm-score-pill">
                <span className="score-num-lg">{kw.score}</span>
                <span className="score-of">/ 100</span>
              </span>
              <Outcome value={outcome} revenue={revenue ? +revenue : null}/>
            </div>
          </div>
          <div className="dm-head-actions">
            <button className="btn btn-ghost sm" onClick={copyTab} title="복사 (⌘C)">
              <span className="btn-ico">⧉</span> 복사
            </button>
            <button className="dm-close" onClick={onClose} title="닫기 (Esc)">×</button>
          </div>
        </header>

        <nav className="dm-tabs">
          {tabs.map(t => (
            <button key={t.id} className={"dm-tab " + (tab === t.id ? "active" : "")} onClick={() => setTab(t.id)}>
              <span className="dm-tab-ico">{t.ico}</span>
              <span>{t.lbl}</span>
              {t.badge && <span className="dm-tab-badge">{t.badge}</span>}
            </button>
          ))}
          <div className="dm-tab-spacer"/>
          <span className="dm-kbd-hint"><Kbd>←</Kbd><Kbd>→</Kbd> 탭 · <Kbd>J</Kbd><Kbd>K</Kbd> 스크롤 · <Kbd>Esc</Kbd> 닫기</span>
        </nav>

        <div className="dm-body">
          <aside className="dm-rail">
            <div className="dm-rail-section">
              <div className="dm-rail-lbl">정량 지표</div>
              <div className="dm-rail-stats">
                <RailStat label="로켓%" value={`${kw.rocketPct}%`} bar={kw.rocketPct} hint={kw.rocketPct < 30 ? "진입 적합" : kw.rocketPct < 50 ? "보통" : "포화"}/>
                <RailStat label="판매자로켓" value={`${sellerRocket}개`} bar={Math.min(sellerRocket * 3, 100)}/>
                <RailStat label="평균가" value={avgPrice} hint="경쟁 평균"/>
                <RailStat label="리뷰수" value={avgReviews}/>
              </div>
            </div>
            <div className="dm-rail-section">
              <div className="dm-rail-lbl">점수 추이 (8일)</div>
              <Sparkline data={kw.sparkline} width={208} height={42} stroke="var(--accent)" fill="var(--accent-soft)"/>
            </div>
            <div className="dm-rail-section">
              <div className="dm-rail-lbl">실전 결과 입력</div>
              <div className="dm-outcome-form">
                <select className="ctl-input sm" value={outcome} onChange={e => setOutcome(e.target.value)}>
                  <option value="">미입력</option>
                  <option value="sourcing">소싱중</option>
                  <option value="pending">대기</option>
                  <option value="success">성공</option>
                  <option value="fail">실패</option>
                </select>
                <input className="ctl-input sm" type="number" placeholder="매출 (원)" value={revenue} onChange={e => setRevenue(e.target.value)}/>
                <button className="btn btn-primary sm full" onClick={saveOutcome}>저장</button>
              </div>
            </div>
            <div className="dm-rail-section">
              <div className="dm-rail-lbl">메모</div>
              <textarea className="ctl-input sm" rows="3" placeholder="자유 메모 (자동 저장)" value={notes} onChange={e => saveNotes(e.target.value)}></textarea>
            </div>
          </aside>

          <main className="dm-main" ref={bodyRef}>
            {loading && <div style={{textAlign:'center',padding:40,color:'var(--fg-3)'}}>불러오는 중…</div>}
            {!loading && tab === "overview" && <OverviewPane kw={kw} detail={detail}/>}
            {!loading && tab === "opus"     && <OpusPane kw={kw} detail={detail}/>}
            {!loading && tab === "strategy" && <StrategyPane kw={kw} detail={detail}/>}
            {!loading && tab === "cuts"     && <CutsPane kw={kw} detail={detail} onZoom={setZoom}/>}
          </main>
        </div>

        <footer className="dm-foot">
          <div className="dm-foot-left">
            <span className="dm-foot-meta">분석일 {kw.date}</span>
          </div>
          <div className="dm-foot-actions">
            <button className="btn btn-ghost" onClick={() => { AS_API.reanalyze(kw.kw).then(() => showToast('재분석 시작됨')).catch(e => showToast('실패: ' + e.message, 'err')); }}>⚡ 재분석</button>
          </div>
        </footer>

        {toast && <div className={"dm-toast " + toast.kind}>{toast.msg}</div>}

        {zoom !== null && (
          <div className="dm-zoom" onClick={() => setZoom(null)}>
            <div className="dm-zoom-card" onClick={e => e.stopPropagation()}>
              <div className="dm-zoom-head">
                <span>컷 {String(zoom + 1).padStart(2, "0")} — {cutLabel(zoom)}</span>
                <button className="dm-close" onClick={() => setZoom(null)}>×</button>
              </div>
              <div className="dm-zoom-img">
                {cutUrls[zoom]
                  ? <img src={cutUrls[zoom]} alt={`컷 ${zoom+1}`} style={{maxWidth:'100%',maxHeight:'60vh',objectFit:'contain'}}/>
                  : <span className="dm-zoom-letter">{kw.kw.slice(0, 1)}</span>
                }
              </div>
              <div className="dm-zoom-actions">
                <button className="btn btn-ghost sm" onClick={() => setZoom(z => Math.max(0, z - 1))}>← 이전</button>
                <button className="btn btn-ghost sm" onClick={() => setZoom(z => Math.min((cutUrls.length || cutTotal) - 1, z + 1))}>다음 →</button>
              </div>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

function RailStat({ label, value, bar, hint }) {
  return (
    <div className="rail-stat">
      <div className="rs-row">
        <span className="rs-lbl">{label}</span>
        <span className="rs-val">{value}</span>
      </div>
      {typeof bar === "number" && <Bar pct={bar} max={100} color="var(--accent)"/>}
      {hint && <div className="rs-hint">{hint}</div>}
    </div>
  );
}

function OverviewPane({ kw, detail }) {
  const pain = detail?.commonPain || kw.pain || '데이터 없음';
  const killer = detail?.killerFeature || kw.killer || '데이터 없음';
  return (
    <div className="ov2">
      <div className="ov2-hero">
        <div className="ov2-tag">한 줄 요약</div>
        <p className="ov2-headline">
          <q>{killer}</q>로 차별화 가능한 키워드. 로켓 비율 <em>{kw.rocketPct}%</em>로 진입 적합도 <em className={kw.rocketPct < 30 ? "ok" : "warn"}>{kw.rocketPct < 30 ? "높음" : "보통"}</em>.
        </p>
      </div>
      <div className="ov2-grid">
        <div className="ov2-card good">
          <div className="ov2-card-head"><span className="ov2-icon">＋</span><span>킬러 기능</span></div>
          <div className="ov2-card-body">{killer}</div>
        </div>
        <div className="ov2-card bad">
          <div className="ov2-card-head"><span className="ov2-icon">−</span><span>공통 페인포인트</span></div>
          <div className="ov2-card-body">{pain}</div>
        </div>
      </div>
    </div>
  );
}

function parseOpusSections(text) {
  if (!text) return [];
  const sections = [];
  const lines = text.split('\n');
  let current = null;
  for (const line of lines) {
    const headMatch = line.match(/^#{1,3}\s+(.+)/) || line.match(/^[①②③④⑤⑥⑦⑧⑨⑩]\s*(.+)/);
    if (headMatch) {
      if (current) sections.push(current);
      current = { title: headMatch[1].trim(), body: '', quote: '' };
    } else if (current) {
      const quoteMatch = line.match(/^>\s*(.+)/);
      if (quoteMatch) current.quote += (current.quote ? '\n' : '') + quoteMatch[1];
      else current.body += (current.body ? '\n' : '') + line;
    }
  }
  if (current) sections.push(current);
  if (sections.length === 0 && text.trim()) {
    sections.push({ title: 'Opus 분석', body: text.trim(), quote: '' });
  }
  return sections;
}

function OpusPane({ kw, detail }) {
  const raw = detail?.opusJudgment || '';
  if (!raw) return <div style={{color:'var(--fg-3)',padding:20}}>Opus 분석 데이터가 없습니다.</div>;

  const sections = parseOpusSections(raw);
  const tones = ['ok', 'warn', 'bad', 'ok', 'warn', 'bad'];
  const icons = ['①','②','③','④','⑤','⑥','⑦','⑧','⑨','⑩'];

  return (
    <div className="opus2">
      {sections.map((s, i) => (
        <article key={i} className={"opus2-card tone-" + (tones[i % tones.length])}>
          <div className="opus2-num">{icons[i] || (i+1)}</div>
          <div className="opus2-body">
            <h3>{s.title}</h3>
            <p style={{whiteSpace:'pre-wrap'}}>{s.body.trim()}</p>
            {s.quote && <blockquote>{s.quote}</blockquote>}
          </div>
        </article>
      ))}
    </div>
  );
}

function parseStrategySections(text) {
  if (!text) return [];
  const sections = [];
  const lines = text.split('\n');
  let current = null;
  for (const line of lines) {
    const headMatch = line.match(/^#{1,3}\s+(.+)/) || line.match(/^\d+\.\s+\*\*(.+?)\*\*/) || line.match(/^\d+\.\s+(.+)/);
    if (headMatch) {
      if (current) sections.push(current);
      current = { lbl: headMatch[1].replace(/\*\*/g, '').trim(), lines: [] };
    } else if (current) {
      if (line.trim()) current.lines.push(line);
    }
  }
  if (current) sections.push(current);
  if (sections.length === 0 && text.trim()) {
    sections.push({ lbl: '전략', lines: text.trim().split('\n') });
  }
  return sections;
}

function renderMd(text) {
  const parts = [];
  let key = 0;
  const regex = /\*\*(.+?)\*\*/g;
  let last = 0, m;
  while ((m = regex.exec(text)) !== null) {
    if (m.index > last) parts.push(<span key={key++}>{text.slice(last, m.index)}</span>);
    parts.push(<strong key={key++} style={{color:'var(--accent)'}}>{m[1]}</strong>);
    last = regex.lastIndex;
  }
  if (last < text.length) parts.push(<span key={key++}>{text.slice(last)}</span>);
  return parts.length ? parts : text;
}

function StrategyPane({ kw, detail }) {
  const raw = detail?.strategyReport || '';
  if (!raw) return <div style={{color:'var(--fg-3)',padding:20}}>판매 전략 데이터가 없습니다.</div>;

  const steps = parseStrategySections(raw);
  return (
    <div className="strat2">
      {steps.map((s, i) => (
        <div key={i} className="strat2-step">
          <div className="strat2-n">{i + 1}</div>
          <div className="strat2-line"/>
          <div className="strat2-card">
            <div className="strat2-lbl">{renderMd(s.lbl)}</div>
            <div className="strat2-body">
              {s.lines.map((line, j) => {
                const trimmed = line.trim();
                const isList = /^[-*]\s/.test(trimmed) || /^\d+\.\s/.test(trimmed);
                const clean = trimmed.replace(/^[-*]\s+/, '').replace(/^\d+\.\s+/, '');
                if (isList) {
                  return <div key={j} style={{display:'flex',gap:8,padding:'4px 0',lineHeight:1.6}}>
                    <span style={{color:'var(--accent)',flexShrink:0}}>•</span>
                    <span>{renderMd(clean)}</span>
                  </div>;
                }
                if (!trimmed) return <div key={j} style={{height:8}}/>;
                return <div key={j} style={{padding:'4px 0',lineHeight:1.6}}>{renderMd(trimmed)}</div>;
              })}
            </div>
          </div>
        </div>
      ))}
    </div>
  );
}

function cutLabel(i) {
  const labels = ["메인 헤더","킬러 기능 강조","스펙 비교표","기능 설명 1","기능 설명 2","사용 시나리오","후기 인용","패키지 구성","AS 안내","사이즈 가이드","주의사항","FAQ","구매 혜택","푸터/CTA"];
  return labels[i] || `컷 ${i + 1}`;
}

function parseCutCopies(templateText) {
  if (!templateText) return [];
  // "메인 카피" 다음에 나오는 첫 번째 비어있지 않은 줄을 컷별 카피로 추출
  // 일부는 표 형식, 일부는 일반 텍스트라 둘 다 처리
  const copies = [];
  const lines = templateText.split('\n');
  for (let i = 0; i < lines.length; i++) {
    const line = lines[i].trim();
    if (/^메인\s*카피/.test(line) || line === '메인 카피' || line.startsWith('| 메인 카피')) {
      // 같은 줄에 카피가 있는 경우 (탭/파이프 구분)
      let copyText = line.replace(/^메인\s*카피\s*[\t|]?\s*/, '').replace(/^\|\s*메인\s*카피\s*\|\s*/, '').replace(/\s*\|.*$/, '').trim();
      // 빈 줄 다음 비어있지 않은 줄에서 추출
      if (!copyText) {
        for (let j = i + 1; j < Math.min(i + 5, lines.length); j++) {
          const next = lines[j].trim();
          if (next && !next.startsWith('|') && !next.startsWith('---') && !/^[가-힣]+ 카피/.test(next)) {
            copyText = next.replace(/^["']|["']$/g, ''); break;
          }
        }
      }
      if (copyText && copyText.length > 1 && copyText.length < 200) copies.push(copyText);
    }
  }
  return copies;
}

function CutsPane({ kw, detail, onZoom }) {
  const images = detail?.generatedImages;
  const urls = images?.urls || [];
  const progress = images?.progress;
  const total = 14;
  const done = urls.length;
  const running = progress?.running ? 1 : 0;
  const cutCopies = parseCutCopies(detail?.template?.text);

  const [toastMsg, setToastMsg] = useState_M(null);
  const showToast = (msg, kind = 'ok') => {
    setToastMsg({ msg, kind });
    setTimeout(() => setToastMsg(null), 4000);
  };

  const downloadOne = (url, idx) => {
    const a = document.createElement('a');
    a.href = url;
    a.download = `${kw.kw}_cut${String(idx + 1).padStart(2, '0')}.png`;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
  };
  const downloadAll = async () => {
    for (let i = 0; i < urls.length; i++) {
      downloadOne(urls[i], i);
      await new Promise(r => setTimeout(r, 300));
    }
    showToast(`📥 ${urls.length}장 다운로드 시작됨`);
  };

  const queueTemplate = async () => {
    try {
      await AS_API.queueAdd({ keyword: kw.kw, grade: kw.grade, score: kw.score });
      showToast(`✅ "${kw.kw}" 기획서 큐 추가 완료 — template_worker가 2분 내 자동 실행`);
    } catch (e) { showToast('❌ 실패: ' + (e.error || e.message), 'err'); }
  };
  const generateImages = async () => {
    if (done > 0 && !confirm(`이미 ${done}컷 생성됨. 다시 생성하면 기존 이미지를 덮어씁니다. 계속할까요?`)) return;
    if (done === 0 && !confirm(`14컷 이미지 생성을 시작합니다 (Gemini, 약 13분 소요). 진행할까요?`)) return;
    try {
      await AS_API.generateImages(kw.kw);
      showToast(`🎨 "${kw.kw}" 14컷 이미지 생성 시작 — 1:1 정사각형, 약 13분 후 표시`);
    } catch (e) { showToast('❌ 실패: ' + (e.error || e.message), 'err'); }
  };

  return (
    <div className="cuts2">
      {toastMsg && (
        <div style={{position:'fixed',top:80,left:'50%',transform:'translateX(-50%)',zIndex:9999,padding:'12px 20px',background:toastMsg.kind==='err'?'oklch(0.5 0.18 25)':'oklch(0.5 0.16 145)',color:'#fff',borderRadius:8,fontSize:13,fontWeight:500,boxShadow:'0 8px 24px rgba(0,0,0,0.4)'}}>
          {toastMsg.msg}
        </div>
      )}
      <div className="cuts2-summary">
        <div className="cuts2-progress">
          <div className="cuts2-bar"><div className="cuts2-bar-fill" style={{ width: (done / total * 100) + "%" }}></div></div>
          <span className="cuts2-count">{done} / {total} 컷 완료</span>
        </div>
        <div className="cuts2-legend">
          <span><span className="dot ok"></span>완료 {done}</span>
          {running > 0 && <span><span className="dot run"></span>생성중 {running}</span>}
          <span><span className="dot empty"></span>대기 {total - done - running}</span>
        </div>
        <div style={{display:'flex',gap:8,marginTop:10,flexWrap:'wrap'}}>
          <button className="btn btn-ghost sm" onClick={queueTemplate} title="detail_template.js 실행 → 14컷 기획서 + cut_mapping.json 생성">📋 기획서 큐 추가</button>
          <button className="btn btn-primary sm" onClick={generateImages} title="generate_cut_images.js 실행 → Gemini로 14컷 이미지 생성">{done > 0 ? '🔄 컷 재생성' : '🎨 14컷 이미지 생성'}</button>
          {done > 0 && (
            <button className="btn btn-ghost sm" onClick={downloadAll} title="모든 컷 이미지 다운로드">📥 전체 다운로드 ({done}장)</button>
          )}
        </div>
        {done === 0 && <div style={{color:'var(--fg-4)',fontSize:12,marginTop:6}}>이미지 없음. 먼저 "기획서 큐 추가" → 2분 후 "14컷 이미지 생성" 순서로 진행.</div>}
      </div>
      <div className="cuts2-grid">
        {Array.from({ length: total }).map((_, i) => {
          const hasImg = i < urls.length;
          const state = hasImg ? "done" : "empty";
          const copy = cutCopies[i];
          return (
            <button key={i} className={"cut2 state-" + state} onClick={() => hasImg && onZoom(i)} style={{position:'relative'}}>
              <div className="cut2-num">{String(i + 1).padStart(2, "0")}</div>
              {hasImg && (
                <button onClick={(e) => { e.stopPropagation(); downloadOne(urls[i], i); }} title="이 컷 다운로드" style={{position:'absolute',top:6,right:6,zIndex:2,background:'rgba(0,0,0,0.65)',color:'#fff',border:'none',borderRadius:4,padding:'2px 7px',fontSize:12,cursor:'pointer'}}>⬇</button>
              )}
              <div className={"cut2-img " + state}>
                {hasImg ? <img src={urls[i]} alt={`컷 ${i+1}`} style={{width:'100%',height:'100%',objectFit:'cover',borderRadius:6}}/> : null}
              </div>
              <div className="cut2-cap">{cutLabel(i)}</div>
              {copy && (
                <div style={{fontSize:11,color:'var(--accent)',marginTop:4,padding:'4px 6px',background:'rgba(124,92,255,0.08)',borderRadius:4,lineHeight:1.3,minHeight:34,display:'-webkit-box',WebkitLineClamp:2,WebkitBoxOrient:'vertical',overflow:'hidden',textAlign:'left'}} title={copy}>
                  💬 {copy}
                </div>
              )}
              <div className="cut2-state-row">
                <span className={"cut2-state-dot " + state}></span>
                <span className="cut2-state-lbl">{hasImg ? "완료" : "대기"}</span>
              </div>
            </button>
          );
        })}
      </div>
    </div>
  );
}

Object.assign(window, { DetailModal });
