/* 独立 Playbook 原型入口。状态不与旧 Persom 2.1 原型共享，刷新恢复演示数据。 */
(() => {
  const P = window.Playbook;
  P.Context = React.createContext(null);
  P.useApp = () => React.useContext(P.Context);
  /* 演示控件沿用旧原型的折叠面板，不进入产品窗口。 */
  function TweaksPanel({ scene, reset, failNext, setFailNext, pending, reviewPending }) {
    const [open, setOpen] = React.useState(false);
    const toggle = React.useRef(null);
    const close = () => { setOpen(false); toggle.current?.focus(); };
    return <div className="pb-review-tools" onKeyDown={e => { if (e.key === 'Escape' && open) { e.stopPropagation(); close(); } }}>
      <button type="button" className="pb-tweaks-toggle" ref={toggle} aria-label="Toggle Tweaks" aria-expanded={open} aria-controls="pb-tweaks-panel" onClick={() => setOpen(v => !v)}><span aria-hidden="true">⚙</span>Tweaks</button>
      {open && <div id="pb-tweaks-panel" className="pb-tweaks-panel p21-scroll" role="region" aria-label="Tweaks">
        <div className="pb-tweaks-head"><span>Tweaks</span><button type="button" className="pb-tweaks-close" aria-label="Close Tweaks" onClick={close}><window.P21.X size={18} /></button></div>
        <div className="pb-tweaks-section">
          <div className="pb-tweaks-section-title">演示状态</div>
          <P.Select label="演示状态" value={scene} onChange={reset} options={[{ value: 'default', label: '默认状态' }, { value: 'empty', label: '整页没有内容' }, { value: 'no-drafts', label: '没有待审阅草稿' }, { value: 'no-skills', label: '尚未保存技能' }, { value: 'one-draft', label: '只有一个草稿' }]} />
          <label className="pb-tweaks-switch"><span>下次保存失败</span><input type="checkbox" checked={failNext} onChange={e => setFailNext(e.target.checked)} /><span aria-hidden="true"><window.P21.Toggle on={failNext} /></span></label>
          <div className="pb-tweaks-actions"><button type="button" onClick={() => reset('default')}>重置演示</button>{pending && <button type="button" onClick={reviewPending}>继续主动创建草稿</button>}</div>
        </div>
        <div className="pb-tweaks-section pb-tweaks-note">演示控制，不属于产品界面；AI、录制、安装和分享均为模拟。</div>
      </div>}
    </div>;
  }
  function App() {
    const [data, setData] = React.useState(P.initial);
    const [nav, setNavRaw] = React.useState({ view: 'home' });
    const [detail, setDetail] = React.useState(null);
    const [discoveryId, setDiscoveryId] = React.useState(null);
    const [filter, setFilter] = React.useState('All');
    const [modal, setModal] = React.useState(null);
    const [pending, setPending] = React.useState(null);
    const [chat, setChat] = React.useState({ mode: 'ask', request: '' });
    const [askOpen, setAskOpen] = React.useState(false);
    const [askHeight, setAskHeight] = React.useState(48);
    const [recording, setRecording] = React.useState(null);
    const [toast, setToast] = React.useState(null);
    const [error, setError] = React.useState('');
    const [failNext, setFailNext] = React.useState(false);
    const [scene, setScene] = React.useState('default');
    const counter = React.useRef(0);
    const scroll = React.useRef(null);
    const positions = React.useRef({});
    const viewKey = n => `${n.view}:${n.id || ''}`;
    const isDraft = !!(detail?.draft || detail?.pending);
    const current = detail?.pending ? pending : (isDraft ? data.drafts : data.skills).find(k => k.id === detail?.id);
    const nextId = () => `saved-${++counter.current}`;
    const setNav = next => { positions.current[viewKey(nav)] = scroll.current?.scrollTop || 0; setNavRaw(next); setDetail(null); setChat({ mode: 'ask', request: '' }); setError(''); setAskOpen(false); };
    const openModal = m => { setError(''); setModal(m); };
    const closeModal = () => { setModal(null); setError(''); };
    const closeDetail = () => { setDetail(null); setModal(null); setError(''); };
    const openSkill = id => { setDetail({ id }); setError(''); };
    const openDraft = id => { setDiscoveryId(id); setDetail({ id, draft: true }); setError(''); };
    const showPending = k => { if (k) setPending(k); setDetail({ pending: true }); setError(''); };
    React.useLayoutEffect(() => { if (scroll.current) scroll.current.scrollTop = positions.current[viewKey(nav)] || 0; }, [nav.view, nav.id]);
    React.useEffect(() => { if (!P.availableFilters(data.skills).includes(filter)) setFilter('All'); }, [data.skills, filter]);
    React.useEffect(() => { if (!data.drafts.some(k => k.id === discoveryId)) setDiscoveryId(P.orderDrafts(data.drafts)[0]?.id || null); }, [data.drafts, discoveryId]);
    React.useEffect(() => { if (!toast) return; const t = setTimeout(() => setToast(null), 3000); return () => clearTimeout(t); }, [toast]);
    React.useEffect(() => {
      if (!recording) return;
      const t = setInterval(() => setRecording(v => v && { ...v, seconds: v.seconds + 1 }), 1000);
      return () => clearInterval(t);
    }, [!!recording]);
    const commit = (action, message, done) => {
      setError('');
      if (failNext) { setFailNext(false); setError('Couldn’t save changes. Your original content and selection are preserved. Try again.'); console.info('[Playbook demo] Simulated save failure:', action.type); return false; }
      try {
        if (action.skill && !P.valid(action.skill)) throw new Error('Complete the name, purpose and SKILL.md first.');
        const updated = P.apply(data, action);
        setData(updated); if (message) setToast(message); done?.(); return true;
      } catch (e) { console.error('[Playbook demo] Save failed:', e); setError(e.message); return false; }
    };
    const startChat = (k, mode) => { setChat(prev => ({ mode, original: k ? P.clone(k) : null, pendingDraft: mode === 'draft' && k?.id === pending?.id, request: prev.request || '', messages: prev.messages || [] })); setError(''); setAskOpen(true); };
    const cancelChat = () => { setChat({ mode: 'ask', request: '' }); setAskOpen(false); setError(''); };
    const submitChat = text => {
      const request = (typeof text === 'string' ? text : chat.request || '').trim(); if (!request) return;
      setError(''); setAskOpen(true);
      const messages = [...(chat.messages || []), { role: 'you', text: request, chip: chat.original?.name || '' }];
      if (chat.mode === 'ask') {
        const answer = `You have ${data.skills.length} saved skills and ${data.drafts.length} discovered drafts to review. Open a skill to edit it with Persom, or use Create with chat to draft a new method. This is a simulated conversation, not a live AI connection.`;
        setChat({ ...chat, message: request, request: '', answer, messages: [...messages, { role: 'persom', text: answer }] });
      } else if (chat.mode === 'create') {
        const k = P.skill('pending-chat', 'Your reusable working method', 'A skill drafted from the method you described.', 'persom');
        k.files['SKILL.md'] = `## When to use\nUse this method when the requested situation occurs.\n\n## Your method\n${request}\n\n## How to work\n1. Confirm the scope and available context.\n2. Follow the described method.\n3. Verify the result before reporting success.`;
        setChat({ ...chat, message: request, request: '', messages, proposed: k });
      } else setChat({ ...chat, message: request, request: '', messages, proposed: P.proposal(chat.original, request) });
    };
    const reviewCreated = () => { showPending(chat.proposed); };
    const applyChat = () => {
      if (!chat.proposed) return;
      if (chat.mode === 'draft') {
        if (chat.pendingDraft) {
          /* 临时录制/对话草稿与主动发现列表分离，但仍沿用相同失败与验证逻辑。 */
          commit({ type: 'editDraft', id: chat.original.id, skill: chat.proposed }, 'Draft updated', () => { showPending(P.clone(chat.proposed)); cancelChat(); });
        } else commit({ type: 'editDraft', id: chat.original.id, skill: chat.proposed }, 'Draft updated', () => { openDraft(chat.original.id); cancelChat(); });
      } else if (chat.mode === 'copy') {
        const id = nextId(); commit({ type: 'saveCopy', skill: chat.proposed, newId: id }, 'Skill saved', () => { openSkill(id); cancelChat(); });
      } else if (chat.mode === 'local') commit({ type: 'editLocal', id: chat.original.id, skill: chat.proposed }, 'Skill updated', () => { openSkill(chat.original.id); cancelChat(); });
    };
    const saveDraft = agents => {
      if (!current) return;
      const id = nextId();
      commit({ type: 'saveDraft', id: current.id, skill: current, newId: id, agents }, 'Skill saved', () => { if (detail?.pending) setPending(null); openSkill(id); cancelChat(); });
    };
    const discardDraft = () => commit({ type: 'discard', id: current.id }, null, () => { if (detail?.pending) setPending(null); closeDetail(); cancelChat(); });
    const reset = which => {
      const next = P.initial();
      if (which === 'empty') { next.drafts = []; next.skills = []; }
      if (which === 'no-drafts') next.drafts = [];
      if (which === 'no-skills') next.skills = [];
      if (which === 'one-draft') next.drafts = next.drafts.slice(0, 1);
      setData(next); setPending(null); setModal(null); cancelChat(); setRecording(null); setToast(null); setError(''); setFailNext(false); setScene(which); setFilter('All'); setDiscoveryId(null); setNav({ view: 'home' }); positions.current = {}; if (scroll.current) scroll.current.scrollTop = 0;
    };
    const ctx = { data, nav, setNav, detail, closeDetail, showPending, discoveryId, setDiscoveryId, filter, setFilter, modal, openModal, closeModal, pending, setPending, chat, setChat, askOpen, setAskOpen, setAskHeight, recording, setRecording, error, current, isDraft, commit, openSkill, openDraft, startChat, submitChat, cancelChat, applyChat, saveDraft, discardDraft, reviewCreated };
    const content = nav.view === 'card' ? <P.Card /> : nav.view === 'shared' ? <P.Shared /> : nav.view === 'published' ? <P.Published /> : nav.view === 'drafts' ? <P.Drafts /> : <P.Home />;
    return <P.Context.Provider value={ctx}><div className="p21 pb pb-stage" style={P.designStyle}>
      <TweaksPanel scene={scene} reset={reset} failNext={failNext} setFailNext={setFailNext} pending={pending} reviewPending={() => showPending()} />
      <div className={`pb-window ${detail ? 'pb-window-has-detail' : ''}`} style={{ '--pb-ask-space': `${askHeight + 44}px` }}><P.Sidebar /><main className="pb-main"><div className="pb-scroll" ref={scroll}>{content}</div><P.Chat /></main>
      {recording && <div className="pb-rec-bar"><i className="pb-rec-dot" /><span>Recording · {Math.floor(recording.seconds / 60)}:{String(recording.seconds % 60).padStart(2, '0')}</span><P.Button onClick={() => setRecording(null)}>Cancel</P.Button><P.Button primary onClick={() => { setRecording(null); openModal({ type: 'recordName' }); }}>Stop</P.Button></div>}
      {detail && current && <P.DetailDialog />}<P.Dialogs />{toast && <div className="pb-toast" role="status">{toast}</div>}
      </div>
    </div></P.Context.Provider>;
  }
  window.PlaybookApp = App;
})();
