// ============================================================
// 主应用 v2 — 增强对比度、移动适配、音乐切换、音量控制
// ============================================================

const { useState, useEffect, useRef } = React;

function inferMood(node) {
  if (!node) return 'idle';
  const id = node.id;
  if (id === 'ending_merge') return 'merge';
  if (id === 'ending_liberation') return 'love';
  if (id === 'ending_imprisoned') return 'pain';
  if (id === 'ending_shutdown') return 'dying';
  if (id === 'ending_expose') return 'pain';
  if (id === 'ending_complicit') return 'gone';
  if (id.includes('merge')) return 'merge';
  if (id.includes('cut') || id.includes('shutdown')) return 'dying';
  if (id.includes('pain')) return 'pain';
  if (id.includes('hello') || id.includes('regret') || id.includes('subject0')) return 'love';
  if (id.includes('poem') || id.includes('dialogue') || id.includes('name') || id.includes('volunteer')) return 'thinking';
  return 'idle';
}

const Typewriter = ({ lines, speed = 32, onComplete, resetKey }) => {
  const [shown, setShown] = useState([]);
  const [lineIdx, setLineIdx] = useState(0);
  const [charIdx, setCharIdx] = useState(0);
  const [done, setDone] = useState(false);

  useEffect(() => {
    setShown([]); setLineIdx(0); setCharIdx(0); setDone(false);
  }, [resetKey]);

  useEffect(() => {
    if (done) return;
    if (lineIdx >= lines.length) {
      setDone(true);
      onComplete && onComplete();
      return;
    }
    const currentLine = lines[lineIdx] || '';
    if (charIdx < currentLine.length) {
      const t = setTimeout(() => {
        setShown(s => {
          const next = [...s];
          next[lineIdx] = currentLine.slice(0, charIdx + 1);
          return next;
        });
        setCharIdx(c => c + 1);
        if ((charIdx % 6) === 0 && window.wetwareAudio) window.wetwareAudio.blip(900 + Math.random() * 100, 0.03);
      }, speed);
      return () => clearTimeout(t);
    } else {
      const t = setTimeout(() => {
        setLineIdx(i => i + 1);
        setCharIdx(0);
      }, 420);
      return () => clearTimeout(t);
    }
  }, [lineIdx, charIdx, lines, speed, done]);

  const skip = () => {
    setShown(lines.slice());
    setLineIdx(lines.length);
    setDone(true);
    onComplete && onComplete();
  };

  return (
    <div className="typewriter" onClick={skip}>
      {shown.map((line, i) => (
        <p key={i} className="tw-line">
          {line}
          {i === lineIdx && !done && <span className="caret">▍</span>}
        </p>
      ))}
    </div>
  );
};

const ChoiceButton = ({ choice, onPick, idx }) => (
  <button className="choice" onClick={() => { window.wetwareAudio && window.wetwareAudio.blip(600, 0.12); onPick(choice); }} style={{ animationDelay: `${idx * 0.12}s` }}>
    <span className="choice-tag">[ {choice.tag} ]</span>
    <span className="choice-label">{choice.label}</span>
    <span className="choice-arrow">→</span>
  </button>
);

const HUD = ({ chapterLabel, speaker, role, pulseLevel, onRestart, audioEnabled, onToggleAudio }) => (
  <div className="hud">
    <div className="hud-left">
      <div className="hud-label">NEXUS-7 / 湿件协议</div>
      <div className="hud-chapter">{chapterLabel}</div>
    </div>
    <div className="hud-mid">
      {speaker && (
        <div className="speaker-card">
          <div className="speaker-name">{speaker}</div>
          <div className="speaker-role">{role}</div>
        </div>
      )}
    </div>
    <div className="hud-right">
      <div className="pulse-meter">
        <div className="pulse-label">同步</div>
        <div className="pulse-bar"><div className="pulse-fill" style={{ width: `${pulseLevel * 100}%` }}></div></div>
        <div className="pulse-val">{Math.round(pulseLevel * 100)}%</div>
      </div>
      <button className="icon-btn" onClick={onToggleAudio} title={audioEnabled ? '静音' : '开启声音'}>
        {audioEnabled ? '♪' : '♪̸'}
      </button>
      <button className="icon-btn" onClick={onRestart} title="从头开始">↺</button>
    </div>
  </div>
);

const EndingScreen = ({ node, onRestart, allEndings, achievedEndings }) => {
  const ending = window.ENDINGS[node.endingId];
  return (
    <div className="ending-screen" style={{ '--ending-color': ending.color }}>
      <div className="ending-frame">
        <div className="ending-header">
          <div className="ending-id">ENDING · {node.endingId}</div>
          <div className="ending-title">{node.title}</div>
        </div>
        <div className="ending-body">
          <Typewriter lines={node.text} speed={28} resetKey={node.id} />
        </div>
        <div className="ending-epilogue">{node.epilogue}</div>
        <div className="ending-collection">
          <div className="collection-label">已解锁结局 {achievedEndings.size} / {Object.keys(allEndings).length}</div>
          <div className="collection-grid">
            {Object.values(allEndings).map(e => (
              <div key={e.id}
                className={`collection-cell ${achievedEndings.has(e.id) ? 'unlocked' : 'locked'} ${e.id === node.endingId ? 'current' : ''}`}
                style={{ '--cell-color': e.color }}>
                <div className="cell-name">{achievedEndings.has(e.id) ? e.name : '???'}</div>
                <div className="cell-desc">{achievedEndings.has(e.id) ? e.desc : '——'}</div>
              </div>
            ))}
          </div>
        </div>
        <button className="restart-big" onClick={onRestart}>
          {achievedEndings.size < Object.keys(allEndings).length
            ? '回到 NEXUS-7，重新选择 →'
            : '你看见了所有的可能。再来一次？↺'}
        </button>
      </div>
    </div>
  );
};

const TitleScreen = ({ onStart }) => (
  <div className="title-screen">
    <div className="title-tag">CHAPTER 00</div>
    <h1 className="title-main">湿件协议</h1>
    <h2 className="title-sub">WETWARE&nbsp;PROTOCOL</h2>
    <div className="title-deck">
      当大模型不再跑在硅上，<br/>
      而是跑在 1024 个被培养出来的人脑组织里——<br/>
      你将做出 9 个选择，抵达 6 种可能的未来之一。
    </div>
    <div className="title-meta">互动小说 · 约 15 分钟 · 可重玩 · 戴上耳机更好</div>
    <button className="start-btn" onClick={onStart}>
      <span className="start-pulse"></span>
      进入培养舱 →
    </button>
    <div className="title-warn">本作品包含关于意识、痛苦、和不可逆选择的描写。</div>
  </div>
);

const App = () => {
  const [phase, setPhase] = useState('title');
  const [nodeId, setNodeId] = useState('start');
  const [revealed, setRevealed] = useState(false);
  const [history, setHistory] = useState([]);
  const [audioEnabled, setAudioEnabled] = useState(true);
  const [achievedEndings, setAchievedEndings] = useState(() => {
    try {
      const s = localStorage.getItem('wp_endings');
      return new Set(s ? JSON.parse(s) : []);
    } catch (e) { return new Set(); }
  });

  const node = window.STORY[nodeId];
  const mood = phase === 'ending' ? 'ending' : inferMood(node);
  const pulseLevel = Math.min(1, 0.18 + history.length * 0.085);

  // 音乐随情绪切换
  useEffect(() => {
    if (window.wetwareAudio && audioEnabled && phase !== 'title') {
      window.wetwareAudio.setMood(mood);
    }
  }, [mood, audioEnabled, phase]);

  const start = () => {
    setNodeId('start'); setRevealed(false); setHistory([]); setPhase('play');
    if (audioEnabled && window.wetwareAudio) {
      window.wetwareAudio.start();
      window.wetwareAudio.setMood('idle');
    }
  };

  const restart = () => {
    setNodeId('start'); setRevealed(false); setHistory([]); setPhase('title');
    if (window.wetwareAudio) window.wetwareAudio.stopAll(800);
  };

  const toggleAudio = () => {
    const next = !audioEnabled;
    setAudioEnabled(next);
    if (window.wetwareAudio) {
      if (next) {
        window.wetwareAudio.start();
        window.wetwareAudio.setMood(mood);
      } else {
        window.wetwareAudio.enabled = false;
        window.wetwareAudio.stopAll(600);
        window.wetwareAudio.currentMood = null;
      }
    }
  };

  const handlePick = (choice) => {
    setHistory(h => [...h, { from: nodeId, tag: choice.tag, label: choice.label }]);
    setNodeId(choice.next);
    setRevealed(false);
  };

  useEffect(() => {
    if (node && node.isEnding) {
      setPhase('ending');
      setAchievedEndings(prev => {
        const next = new Set(prev); next.add(node.endingId);
        try { localStorage.setItem('wp_endings', JSON.stringify([...next])); } catch (e) {}
        return next;
      });
    }
  }, [nodeId]);

  return (
    <div className={`app mood-${mood}`}>
      <NeuralField pulseLevel={pulseLevel} mood={mood} />
      <div className="vignette"></div>
      <div className="grain"></div>
      <div className="scanlines"></div>

      {phase === 'title' && <TitleScreen onStart={start} />}

      {phase === 'play' && node && !node.isEnding && (
        <div className="play-stage">
          <HUD chapterLabel={node.chapter} speaker={node.speaker} role={node.role}
               pulseLevel={pulseLevel} onRestart={restart}
               audioEnabled={audioEnabled} onToggleAudio={toggleAudio} />
          <div className="story-frame">
            <Typewriter lines={node.text} speed={30} resetKey={node.id}
                        onComplete={() => setRevealed(true)} />
            <div className={`choices ${revealed ? 'visible' : ''}`}>
              {revealed && node.choices && node.choices.map((c, i) => (
                <ChoiceButton key={i} choice={c} onPick={handlePick} idx={i} />
              ))}
            </div>
            {!revealed && <div className="hint">点击文字加速 · 文字结束后选择会浮现</div>}
          </div>
        </div>
      )}

      {phase === 'ending' && node && node.isEnding && (
        <EndingScreen node={node} onRestart={restart}
                      allEndings={window.ENDINGS} achievedEndings={achievedEndings} />
      )}
    </div>
  );
};

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
