const { useState, useEffect, useRef } = React;
const cx = (...a) => a.filter(Boolean).join(' ');
const q = (k) => new URLSearchParams(location.search).get(k);
const S2 = q('s') === '2'; // 评审：直接进结果
const G = q('g') === '1';  // 评审：冻结在合成中
const REDUCE = !!(window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches);

function Btn({ v = 'glass', size, icon, block, children, ...rest }) {
  return (
    <button className={cx('btn', v, size, block && 'block', !children && 'icon')} {...rest}>
      {icon && <Icon name={icon} size={size === 'xl' ? 20 : 18} />}
      {children}
    </button>
  );
}
function Phone({ children }) {
  return (
    <div className="phone">
      <div className="pscreen">{children}</div>
      <div className="island"></div>
      <div className="phome"></div>
    </div>
  );
}

/* ============ AI 客厅合成 ============ */
const MODELS = [
  { id: 'e8s', name: '海信 85 E8S', short: '海信 E8S', panel: 'RGB-MiniLED' },
  { id: 'g5', name: 'LG 65 G5', short: 'LG G5', panel: 'OLED evo' },
  { id: 'sny', name: 'Sony BRAVIA 8 II', short: 'Sony B8 II', panel: 'QD-OLED' },
  { id: 'tcl', name: 'TCL 85 Q10K', short: 'TCL Q10K', panel: 'Mini LED' },
];
const REF = 85;                     // 预览样片里那台电视的实际尺寸（英寸）
const DISTS = [240, 280, 320];      // 沙发距离候选（cm），默认 280
// 电视在照片卡中的位置（卡与照片同为 4:3，坐标即百分比）
const TVRECT = { wall: { cx: 62, cy: 40.5, w: 33.5, h: 28 }, stand: { cx: 61.5, cy: 45.5, w: 34, h: 28 } };
const viewAngle = (size, dist) => Math.round(2 * Math.atan((size * 2.54 * 0.8716 / 2) / dist) * 180 / Math.PI);
const fitLabel = (a) => a < 28 ? { t: '偏小', cls: 'warn' } : a <= 40 ? { t: '推荐', cls: 'ok' } : { t: '偏大', cls: 'warn' };
const T = { toResult: 1300 }; // 需 ≥ 所有合成动画收尾（bloom .3+.9=1.2s / scan .1+1.15=1.25s）；reduced 时快进

function ComposeApp({ onBack }) {
  const [phase, setPhase] = useState(G ? 'gen' : S2 ? 'result' : 'capture'); // capture | gen | result
  const [size, setSize] = useState(q('sz') ? +q('sz') : REF);
  const [midx, setMidx] = useState(0);
  const [mount, setMount] = useState(q('m') === 'stand' ? 'stand' : 'wall');
  const [dist, setDist] = useState(280);
  const timers = useRef([]);
  const clear = () => { timers.current.forEach(clearTimeout); timers.current = []; };
  useEffect(() => clear, []);

  const shoot = () => {
    if (phase !== 'capture') return;
    setPhase('gen');
    timers.current.push(setTimeout(() => setPhase('result'), REDUCE ? 320 : T.toResult));
  };
  const reset = () => { clear(); setSize(REF); setPhase('capture'); };

  const model = MODELS[midx];
  const angle = viewAngle(size, dist), fit = fitLabel(angle);
  const wCm = Math.round(size * 2.54 * 0.8716), hCm = Math.round(wCm * 9 / 16);
  const shown = phase !== 'capture';
  const resultSrc = mount === 'wall' ? IMG.wall : IMG.stand;

  // AR 尺寸框：以样片实际尺寸(REF)为基准，按所选尺寸等比缩放，套在真实电视位置上
  const tvr = TVRECT[mount], k = size / REF;
  const fp = { left: tvr.cx - tvr.w * k / 2, top: tvr.cy - tvr.h * k / 2, width: tvr.w * k, height: tvr.h * k };

  // 回传 Agent 的结构化载荷（chip 只是它的可视摘要）
  const payload = { size_in: size, width_cm: wCm, mount, model_id: model.id, panel: model.panel, distance_cm: dist, view_angle: angle, fit: fit.t };
  const chips = [`${size}″`, model.panel, mount === 'wall' ? '挂墙' : '底座', `${(dist / 100).toFixed(1)}m`, `视角 ${angle}°`, fit.t];

  return (
    <div className="m-app">
      <div className="vf-bg" style={{ backgroundImage: `url(${shown ? resultSrc : IMG.orig})` }}></div>

      {/* 顶栏 */}
      <div className="m-head">
        {onBack && <button className="mh-back" onClick={onBack} aria-label="返回主页"><Icon name="arrowLeft" size={16} /></button>}
        <span className="mh-logo"><Icon name="sparkle" size={16} /></span>
        <div className="mh-txt">
          <div className="mh-t">AI 客厅合成</div>
          <div className="mh-s">{phase === 'capture' ? '拍下你家电视墙' : phase === 'gen' ? '正在生成合成预览…' : '等比预览 · 尺寸/视角为精算值'}</div>
        </div>
        <span className={cx('mh-step', phase === 'gen' && 'busy')}>{phase === 'capture' ? '拍摄' : phase === 'gen' ? '合成中' : '预览'}</span>
      </div>

      {/* 照片卡 */}
      <div className={cx('vf-wrap', 'p-' + phase)}>
        <div className={cx('vf', 'phase-' + phase)}>
          <img className="vf-img base" src={IMG.orig} alt="客厅原图" draggable="false" />
          <img className="vf-img res" src={IMG.wall} alt="挂墙" draggable="false" style={{ opacity: shown && mount === 'wall' ? 1 : 0 }} />
          <img className="vf-img res" src={IMG.stand} alt="底座" draggable="false" style={{ opacity: shown && mount === 'stand' ? 1 : 0 }} />

          {phase === 'capture' && (
            <div className="vf-guide">
              <span className="gc tl"></span><span className="gc tr"></span><span className="gc bl"></span><span className="gc br"></span>
              <span className="vf-hint">对准电视墙 · 保持水平</span>
            </div>
          )}

          {phase === 'gen' && (
            <React.Fragment>
              <span className="vf-flash"></span>
              <span className="vf-scan"></span>
              <span className="vf-bloom" style={{ left: tvr.cx + '%', top: tvr.cy + '%' }}></span>
              <span className="vf-grid"></span>
            </React.Fragment>
          )}

          {phase === 'result' && (
            <React.Fragment>
              {/* AR 尺寸框：等比套住电视，随尺寸缩放 → 所选即所见 */}
              <div className={cx('size-fp', size === REF && 'ref')} style={{ left: fp.left + '%', top: fp.top + '%', width: fp.width + '%', height: fp.height + '%' }}>
                <span className="fp-c tl"></span><span className="fp-c tr"></span><span className="fp-c bl"></span><span className="fp-c br"></span>
                <span className="fp-lbl">{size}″ · {wCm}×{hCm}cm</span>
              </div>
              <div className="fit-badge">
                <Icon name="crosshair" size={13} />
                <span><b>{size}″</b> ≈ 视角 {angle}°</span>
                <span className={cx('fit-tag', fit.cls)}>{fit.t}</span>
              </div>
            </React.Fragment>
          )}

          <div className={cx('gen-pill', phase === 'gen' && 'on')}>
            <span className="gp-spin"><Icon name="sparkle" size={14} /></span>
            <span>正在生成 <b>{model.short}</b> 的合成预览</span>
          </div>
        </div>
      </div>

      {/* 拍摄条 */}
      <div className={cx('sheet cap-sheet', phase !== 'capture' && 'gone')}>
        <div className="cap-row">
          <button className="cap-side"><Icon name="image" size={20} /><small>相册</small></button>
          <button className="shutter" onClick={shoot} aria-label="拍摄合成"><span></span></button>
          <button className="cap-side"><Icon name="ruler" size={20} /><small>AR 量墙</small></button>
        </div>
        <div className="cap-hint">拍下电视墙，AI 生成等比合成预览；尺寸 / 视角为精算值</div>
      </div>

      {/* 调节面板 */}
      <div className={cx('sheet res-sheet', phase === 'result' && 'on')}>
        <div className="sheet-grip"></div>
        <div className="mseg big">
          {[['wall', '挂墙', 'monitor'], ['stand', '底座', 'layers']].map(([kk, l, ic]) => (
            <button key={kk} className={mount === kk ? 'on' : ''} onClick={() => setMount(kk)}><Icon name={ic} size={15} />{l}</button>
          ))}
        </div>
        <div className="mchips">
          {MODELS.map((m, i) => (
            <button key={m.id} className={cx('mchip', i === midx && 'on')} onClick={() => setMidx(i)}>
              <b>{m.short}</b><small>{m.panel}</small>
            </button>
          ))}
        </div>
        <div className="fld">
          <div className="fld-top"><span className="fld-l">目标尺寸</span><span className="fld-v">{size}″ · {wCm}×{hCm}cm</span></div>
          <input className="mslider" type="range" min="55" max="98" step="1" value={size} onChange={(e) => setSize(+e.target.value)} />
        </div>
        <div className="dist-row">
          <span className="fld-l">沙发距离</span>
          <div className="dist-seg">
            {DISTS.map((d) => <button key={d} className={dist === d ? 'on' : ''} onClick={() => setDist(d)}>{(d / 100).toFixed(1)}m</button>)}
          </div>
          <span className="dist-fit">视角 {angle}° <em className={fit.cls}>{fit.t}</em></span>
        </div>
        <div className="ret-line">
          <span className="ret-k"><Icon name="check" size={12} /> 回传 Agent</span>
          <div className="ret-chips">{chips.map((c) => <span key={c} className="ret-chip">{c}</span>)}</div>
        </div>
        <div className="m-actions">
          <Btn v="glass" icon="refresh" onClick={reset}>重拍</Btn>
          <Btn v="pri" block icon="check">满意 · 存入清单</Btn>
        </div>
      </div>
    </div>
  );
}

/* ============ 采光 · 测光（前台工具 #3） ============
   两轴分离：照度轴 = 锁曝光 EV 反推 lux（快测=估算档，补齐三时段=可信档）；
   反光轴 = AI 识别光源位置（对屏/侧向/顶部）。两轴合成抗反与亮度建议。 */
const LMIN = 30, LMAX = 3000;
const logT = (v) => Math.min(1, Math.max(0, (Math.log(v) - Math.log(LMIN)) / (Math.log(LMAX) - Math.log(LMIN))));
const lux = (ev) => Math.round(2.5 * Math.pow(2, ev)); // ISO 2720：E ≈ 2.5·2^EV（ISO100）
const SLOTS = [
  { k: 'day', l: '白天', ic: 'sun', ev: 7.0 },
  { k: 'dusk', l: '傍晚', ic: 'sunset', ev: 4.5 },
  { k: 'night', l: '夜晚', ic: 'moon', ev: 3.8 },
];
/* agent 识别出的反光源（box 为照片内百分比，按真实样片标注） */
const LSRC = [
  { id: 'win2', ph: 2, n: '对屏侧窗', risk: 'hi', box: { x: 66, y: 10, w: 27, h: 52 } },
  { id: 'lamp2', ph: 2, n: '落地灯', risk: 'mid', box: { x: 1, y: 25, w: 11.5, h: 38 } },
  { id: 'spot2', ph: 2, n: '筒灯×2', risk: 'mid', box: { x: 12.5, y: 1.5, w: 11.5, h: 8.5 } },
  { id: 'win1', ph: 1, n: '侧窗', risk: 'mid', box: { x: 0.6, y: 8, w: 20, h: 50 } },
  { id: 'spot1', ph: 1, n: '筒灯×3', risk: 'mid', box: { x: 43, y: 1.5, w: 21, h: 11.5 } },
  { id: 'cove1', ph: 1, n: '灯带', risk: 'lo', box: { x: 26, y: 6.5, w: 71, h: 6 } },
];
const RISKL = { hi: '高', mid: '中', lo: '低' };

function ABox({ s, i }) {
  const b = s.box;
  return (
    <div className={cx('abox', s.risk)}
      style={{ left: b.x + '%', top: b.y + '%', width: b.w + '%', height: b.h + '%', animationDelay: (0.08 + i * 0.12) + 's' }}>
      <span className="abox-l">{s.n} · {RISKL[s.risk]}</span>
    </div>
  );
}

function LightApp({ onBack }) {
  const LPS = ['turn', 'cap2', 'ana', 'result'];
  const lp0 = LPS.includes(q('lp')) ? q('lp') : 'cap1';
  const [phase, setPhase] = useState(lp0); // cap1 | m1 | turn | cap2 | m2 | ana | result
  const [ev, setEv] = useState(null);
  const [pv, setPv] = useState(q('pv') === '1' ? 1 : 2);       // 结果页当前照片
  const [busySlot, setBusySlot] = useState(null);
  const [meas, setMeas] = useState(() => {
    const m = { day: null, dusk: null, night: null };
    if (lp0 !== 'cap1') m.day = lux(SLOTS[0].ev);
    if (q('slots') === '3') SLOTS.forEach((s) => { m[s.k] = lux(s.ev); });
    return m;
  });
  const timers = useRef([]);
  const T2 = (fn, ms) => timers.current.push(setTimeout(fn, REDUCE ? Math.min(ms, 240) : ms));
  useEffect(() => () => timers.current.forEach(clearTimeout), []);

  // 锁曝光测光：EV 读数 ease-out 逼近目标，落点回调（clearTimeout 亦可清 interval）
  const runMeter = (target, done) => {
    let i = 0; const N = REDUCE ? 4 : 18;
    setEv(Math.round((target - 3.6) * 10) / 10);
    const id = setInterval(() => {
      i++; const k = 1 - i / N;
      setEv(Math.round((target - 3.6 * k * k) * 10) / 10);
      if (i >= N) { clearInterval(id); done(); }
    }, 46);
    timers.current.push(id);
  };
  const shoot1 = () => {
    if (phase !== 'cap1') return; setPhase('m1');
    runMeter(SLOTS[0].ev, () => { setMeas((m) => ({ ...m, day: lux(SLOTS[0].ev) })); T2(() => { setEv(null); setPhase('turn'); }, 460); });
  };
  const shoot2 = () => {
    if (phase !== 'cap2') return; setPhase('m2');
    runMeter(7.4, () => T2(() => {
      setEv(null); setPhase('ana');
      T2(() => setPhase('result'), REDUCE ? 320 : 1450);
    }, 400));
  };
  const reset = () => { timers.current.forEach(clearTimeout); timers.current = []; setMeas({ day: null, dusk: null, night: null }); setEv(null); setPv(2); setBusySlot(null); setPhase('cap1'); };
  const fillSlot = (k) => {
    if (meas[k] != null || busySlot) return; setBusySlot(k);
    T2(() => { setMeas((m) => ({ ...m, [k]: lux(SLOTS.find((s) => s.k === k).ev) })); setBusySlot(null); }, 900);
  };

  const filled = SLOTS.filter((s) => meas[s.k] != null);
  const cred = filled.length === 3;                              // 置信阶梯：3 时段 → 可信档
  const dayLux = meas.day ?? lux(SLOTS[0].ev);
  const band = [Math.round(dayLux / 1.414), Math.round(dayLux * 1.414)]; // ±半档 EV
  const vmin = Math.min(...filled.map((s) => meas[s.k])), vmax = Math.max(...filled.map((s) => meas[s.k]));

  // 二维结论：反光轴（光源位置）× 照度轴（白天上限）
  const hiG = LSRC.some((s) => s.risk === 'hi'), midG = LSRC.some((s) => s.risk === 'mid');
  const arV = hiG ? '必要' : midG ? '建议' : '非必需';
  const brV = dayLux > 200 ? '峰值 ≥1000 nits' : dayLux > 100 ? '峰值 ≥600 nits' : '无高亮需求';
  const chips = [cred ? `全天 ${vmin}–${vmax}lx·可信档` : `白天 ${dayLux}lx·估算档`, '对屏侧窗·高', `抗反·${arV}`, dayLux > 200 ? '≥1000nits' : brV];

  const capturing = ['cap1', 'm1', 'turn', 'cap2', 'm2'].includes(phase);
  const img2on = phase === 'result' ? pv === 2 : ['cap2', 'm2', 'ana'].includes(phase);
  const bg = img2on ? (IMG.rev || IMG.orig) : IMG.orig;
  const wrapCls = phase === 'result' ? 'p-lresult' : phase === 'ana' ? 'p-gen' : 'p-capture';
  const subT = { cap1: '第 1 拍：朝电视墙，锁曝光测照度', m1: '锁曝光 · EV 反推照度…', turn: '转身 180°，拍屏幕对面', cap2: '第 2 拍：对屏方向', m2: '锁曝光 · EV 反推照度…', ana: 'AI 正在识别反光源…', result: cred ? '三时段齐 · 可信档结论' : '快测结论 · 补测时段可升可信档' }[phase];
  const stepT = { cap1: '测光①', m1: '测光①', turn: '转身', cap2: '测光②', m2: '测光②', ana: '识别中', result: '结果' }[phase];

  return (
    <div className="m-app">
      <div className="vf-bg" style={{ backgroundImage: `url(${bg})` }}></div>

      <div className="m-head">
        {onBack && <button className="mh-back" onClick={onBack} aria-label="返回主页"><Icon name="arrowLeft" size={16} /></button>}
        <span className="mh-logo"><Icon name="sun" size={16} /></span>
        <div className="mh-txt">
          <div className="mh-t">采光 · 测光</div>
          <div className="mh-s">{subT}</div>
        </div>
        <span className={cx('mh-step', ['m1', 'm2', 'ana'].includes(phase) && 'busy')}>{stepT}</span>
      </div>

      <div className={cx('vf-wrap', wrapCls)}>
        <div className="vf">
          <img className="vf-img base" src={IMG.orig} alt="朝电视墙" draggable="false" />
          <div className="vf-l2" style={{ opacity: img2on ? 1 : 0 }}>
            {IMG.rev
              ? <img className="vf-img" src={IMG.rev} alt="朝沙发方向" draggable="false" />
              : <div className="vf-ph"><b>「朝沙发方向」样片待生成</b><small>prompts/01-scene-reverse-sofa.md<br />生成后放 aiimage/朝沙发.png，跑 python _mkimg.py</small></div>}
          </div>

          {(phase === 'cap1' || phase === 'cap2') && (
            <div className="vf-guide">
              <span className="gc tl"></span><span className="gc tr"></span><span className="gc bl"></span><span className="gc br"></span>
              <span className="vf-hint">{phase === 'cap1' ? '① 朝电视墙 · 含吸顶灯' : '② 对屏方向 · 含窗与灯'}</span>
            </div>
          )}

          {(phase === 'm1' || phase === 'm2') && (
            <div className="meter">
              <span className="meter-ring"></span>
              <span className="ev-chip">AE-L · EV <b>{(ev ?? 0).toFixed(1)}</b> ≈ {lux(ev ?? 0)} lx</span>
            </div>
          )}

          {phase === 'turn' && (
            <div className="turn-card" onClick={() => setPhase('cap2')}>
              <span className="turn-ic"><Icon name="turn" size={30} /></span>
              <div className="turn-t">转身 180°</div>
              <div className="turn-s">屏幕反射的是它<b>对面</b>的东西——窗、落地灯都在你身后这一侧，拍下来交给 AI 认</div>
              <Btn v="pri" icon="camera" onClick={(e) => { e.stopPropagation(); setPhase('cap2'); }}>已转身 · 拍对屏方向</Btn>
            </div>
          )}

          {phase === 'ana' && (
            <React.Fragment>
              <span className="vf-flash"></span>
              <span className="vf-scan"></span>
              <span className="vf-grid"></span>
            </React.Fragment>
          )}

          {phase === 'result' && LSRC.filter((s) => s.ph === pv).map((s, i) => <ABox key={s.id} s={s} i={i} />)}

          {phase === 'result' && (
            <div className="ppager">
              {[[1, '① 电视墙'], [2, '② 对屏']].map(([n, l]) => (
                <button key={n} className={pv === n ? 'on' : ''} onClick={() => setPv(n)}>{l}</button>
              ))}
            </div>
          )}

          <div className={cx('gen-pill', phase === 'ana' && 'on')}>
            <span className="gp-spin"><Icon name="sparkle" size={14} /></span>
            <span>AI 正在识别<b>反光源</b>与位置…</span>
          </div>
        </div>
      </div>

      {/* 拍摄条 */}
      <div className={cx('sheet cap-sheet', !capturing && 'gone')}>
        <div className="cap-row">
          <button className="cap-side"><Icon name="image" size={20} /><small>相册</small></button>
          <button className="shutter" onClick={phase === 'cap2' ? shoot2 : shoot1} disabled={phase !== 'cap1' && phase !== 'cap2'} aria-label="测光拍摄"><span></span></button>
          <button className="cap-side"><Icon name="lock" size={20} /><small>锁曝光</small></button>
        </div>
        <div className="cap-hint">{phase === 'turn' ? '转身后拍第 2 张：屏幕会反射对面的窗和灯' : phase === 'cap2' || phase === 'm2' ? 'AI 识别对屏反光源（窗 / 落地灯 / 顶灯）' : '锁定曝光，由 EV 反推环境照度（估算档 ±半档）'}</div>
      </div>

      {/* 结果面板 */}
      <div className={cx('sheet lres-sheet', phase === 'result' && 'on')}>
        <div className="sheet-grip"></div>

        <div className="lux-top">
          <div>
            <div className="lux-v">{cred ? `${vmin}–${vmax} lx` : `${dayLux} lx`}</div>
            <div className="lux-sub">{cred ? '全天照度跨度 · 三时段实测' : `白天快测 · 约 ${band[0]}–${band[1]} lx（±半档 EV）`}</div>
          </div>
          <span className={cx('conf-tag', cred && 'ok')}>{cred ? '可信档 · 3/3' : `估算档 · ${filled.length}/3 时段`}</span>
        </div>

        <div className="lgauge">
          <div className="lg-track"></div>
          {!cred && <div className="lg-band" style={{ left: logT(band[0]) * 100 + '%', width: (logT(band[1]) - logT(band[0])) * 100 + '%' }}></div>}
          {[50, 200].map((v) => <span key={v} className="lg-tick" style={{ left: logT(v) * 100 + '%' }}></span>)}
          {[['暗', 40], ['中', 100], ['亮', 700]].map(([l, v]) => <span key={l} className="lg-lbl" style={{ left: logT(v) * 100 + '%' }}>{l} {l === '暗' ? '<50' : l === '中' ? '50–200' : '>200'}</span>)}
          {filled.map((s) => <span key={s.k} className="lg-dot" style={{ left: logT(meas[s.k]) * 100 + '%' }} title={`${s.l} ${meas[s.k]}lx`}></span>)}
        </div>

        <div className="slot-row">
          {SLOTS.map((s) => (
            <button key={s.k} className={cx('slot', meas[s.k] != null && 'done', busySlot === s.k && 'busy')} onClick={() => fillSlot(s.k)}>
              <b><Icon name={s.ic} size={13} />{s.l}</b>
              <small>{busySlot === s.k ? '测光中…' : meas[s.k] != null ? `${meas[s.k]} lx` : '＋补测'}</small>
            </button>
          ))}
        </div>

        <div className="lsec"><Icon name="eye" size={13} />反光源 · AI 识别 {LSRC.length} 处</div>
        <div className="gl-leg">
          {LSRC.map((s) => (
            <span key={s.id} className="gl-it">
              <span className={'dot ' + s.risk}></span><b>{s.n}</b><small>照片{s.ph === 1 ? '①' : '②'}·{RISKL[s.risk]}</small>
            </span>
          ))}
        </div>

        <div className="lrec">
          <div className={cx('lrec-card', hiG && 'hot')}><small>抗反涂层</small><b>{arV}</b></div>
          <div className="lrec-card acc"><small>亮度需求</small><b>{brV}</b></div>
        </div>
        <div className="lrec-why">白天 &gt;200 lx，且对屏方向有大面积侧窗直射入屏——光面屏会出现清晰镜面反射{cred ? `；夜晚 ${meas.night} lx 属暗房，OLED 黑位受益` : ''}</div>
        <div className="gl-row">
          <span className="mfit ok">海信 E8S · 高峰值亮度</span>
          <span className="mfit ok">LG G5 · 抗反膜</span>
          <span className="mfit warn">Sony B8 II · 光面屏慎选</span>
        </div>
        <div className="lnote">照度＝锁曝光 EV 反推（估算，非照度计）；反光＝光源位置判定，非实测眩光</div>

        <div className="ret-line">
          <span className="ret-k"><Icon name="check" size={12} /> 回传 Agent</span>
          <div className="ret-chips">{chips.map((c) => <span key={c} className="ret-chip">{c}</span>)}</div>
        </div>
        <div className="m-actions">
          <Btn v="glass" icon="refresh" onClick={reset}>重测</Btn>
          <Btn v="pri" block icon="check">满意 · 存入清单</Btn>
        </div>
      </div>
    </div>
  );
}

/* ============ stage ============ */
const APPMETA = {
  compose: {
    t: 'AI 客厅合成 · 移动端',
    p: '拍下电视墙，AI 生成等比合成预览；尺寸、视角为精算值。可切挂墙 / 底座、机型、距离，结构化结果回传 Agent。',
    foot: '评审深链：?s=2 结果 · ?g=1 冻结合成中 · ?m=stand 底座 · ?sz=72 指定尺寸',
  },
  light: {
    t: '采光 · 测光 · 移动端',
    p: '两拍测两轴：朝电视墙锁曝光反推照度（快测＝估算档，补齐傍晚 / 夜晚升可信档）；转身拍对屏方向，AI 识别反光源。合成抗反与亮度建议，回传 Agent。',
    foot: '评审深链：?app=light&lp=result（&slots=3 补满时段 · &pv=1 电视墙标注）',
  },
};
function Stage() {
  const [app, setApp] = useState(q('app') === 'light' ? 'light' : 'compose');
  const pick = (a) => {
    if (a === app) return;
    const u = new URL(location); ['app', 'lp', 'slots', 'pv', 's', 'g', 'm', 'sz'].forEach((k) => u.searchParams.delete(k));
    if (a === 'light') u.searchParams.set('app', 'light');
    history.replaceState(null, '', u); setApp(a);
  };
  const M = APPMETA[app];
  return (
    <div className="stage">
      {q('from') === 'home' && (
        <a className="stage-back" href="index.html"><Icon name="arrowLeft" size={14} />主页</a>
      )}
      <div className="stage-head">
        <h1>{M.t}</h1>
        <p>{M.p}</p>
        <div className="app-seg" role="tablist">
          <button className={app === 'compose' ? 'on' : ''} onClick={() => pick('compose')}><Icon name="sparkle" size={15} />AI 客厅合成</button>
          <button className={app === 'light' ? 'on' : ''} onClick={() => pick('light')}><Icon name="sun" size={15} />采光 · 测光</button>
        </div>
        <div className="tag-row">
          <span className="tag ok">Liquid Glass</span>
          <span className="chip">一镜到底动效</span>
          <span className="chip accent">前台交互工具</span>
        </div>
      </div>
      <div className="frames"><Phone key={app}>{app === 'light' ? <LightApp /> : <ComposeApp />}</Phone></div>
      <div className="stage-foot">{M.foot}</div>
    </div>
  );
}

/* 供 电视数据库主页(home.jsx) 壳内嵌入调用；__TV_EMBED 时不自挂载 */
Object.assign(window, { ComposeApp, LightApp });
if (!window.__TV_EMBED) ReactDOM.createRoot(document.getElementById('root')).render(<Stage />);
