/* =========================================================
   三藏閣 — App 셸 + 6탭 헤더 + 라우팅 + 모바일 하단탭 + Tweaks
   ========================================================= */

const { Icon: AIcon } = window;

/* ---------- 검색 ---------- */
function searchAll(query) {
  const q = query.trim();
  if (!q) return [];
  const out = [];
  const re = new RegExp(q.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi');
  for (const id of Object.keys(window.PASSAGES)) {
    const p = window.PASSAGES[id];
    p.paragraphs.forEach((par, i) => {
      if (par.glyph) return;
      const target = (par.body || '') + ' \u00b7 ' + (par.source || '');
      const plain = target.replace(/<[^>]+>/g, '');
      if (re.test(plain)) {
        re.lastIndex = 0;
        const m = re.exec(plain);
        if (!m) return;
        const start = Math.max(0, m.index - 30);
        const end = Math.min(plain.length, m.index + m[0].length + 50);
        const snip = (start > 0 ? '…' : '') +
          plain.slice(start, m.index) +
          '<mark>' + plain.slice(m.index, m.index + m[0].length) + '</mark>' +
          plain.slice(m.index + m[0].length, end) +
          (end < plain.length ? '…' : '');
        out.push({
          passageId: id, paraIndex: i,
          loc: window.CANON_DATA[p.canon].titleAbbr + ' · ' + p.head.kr + ' · ' + par.section,
          snippet: snip,
        });
        re.lastIndex = 0;
      }
    });
  }
  return out.slice(0, 30);
}

/* ---------- Tweaks ---------- */
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "font": "sans",
  "size": 18,
  "lh": 1.85,
  "width": "normal",
  "showOriginal": true,
  "showSource": true,
  "showReading": true,
  "showTranslation": true,
  "showFootnotes": true
}/*EDITMODE-END*/;

const TweaksFloat = ({ open, onClose, settings, setSettings }) => {
  if (!open) return null;
  return (
    <div className="tweaks-float">
      <div className="tweaks-float__head">
        <span>Tweaks · 즉시 변경</span>
        <button className="icon-btn" onClick={onClose}><AIcon name="close" size={18}/></button>
      </div>
      <div className="tweaks-float__body">
        <div className="r-settings__group">
          <div className="r-settings__label"><span>본문 활자</span></div>
          <div className="r-seg" style={{'--n':2}}>
            <button className={'r-seg__btn r-seg__btn-sans' + (settings.font==='sans'?' is-active':'')} onClick={()=>setSettings({...settings, font:'sans'})}>산세리프</button>
            <button className={'r-seg__btn r-seg__btn-serif' + (settings.font==='serif'?' is-active':'')} onClick={()=>setSettings({...settings, font:'serif'})}>명조</button>
          </div>
        </div>
        <div className="r-settings__group">
          <div className="r-settings__label"><span>글자 크기</span><span className="val">{settings.size}px</span></div>
          <input className="r-slider" type="range" min="10" max="36" step="0.5" value={settings.size} onChange={e=>setSettings({...settings, size:+e.target.value})}/>
        </div>
        <div className="r-settings__group">
          <div className="r-settings__label"><span>줄 간격</span><span className="val">{settings.lh.toFixed(2)}</span></div>
          <input className="r-slider" type="range" min="1.5" max="3" step="0.05" value={settings.lh} onChange={e=>setSettings({...settings, lh:+e.target.value})}/>
        </div>
        <div className="r-settings__group">
          <div className="r-settings__label"><span>단 너비</span></div>
          <div className="r-seg" style={{'--n':3}}>
            {['narrow','normal','wide'].map(w=>(
              <button key={w} className={'r-seg__btn'+(settings.width===w?' is-active':'')} onClick={()=>setSettings({...settings, width:w})}>
                {w==='narrow'?'좁게':w==='normal'?'보통':'넓게'}
              </button>
            ))}
          </div>
        </div>
        <div className="r-toggle">
          <div><div className="r-toggle__label">각주 표시</div></div>
          <button className={'r-switch'+(settings.showFootnotes?' is-on':'')} onClick={()=>setSettings({...settings, showFootnotes:!settings.showFootnotes})}/>
        </div>
      </div>
    </div>
  );
};

/* ---------- 상단 내비 (학술지식 구조) ---------- */
const NAV_TABS = [
  { id: 'reader',       kr: '읽기',   placeholder: '원전·번역에서 검색…' },
  { id: 'encyclopedia', kr: '백과',   placeholder: '개념·인물·문헌 항목 검색…' },
  { id: 'dictionary',   kr: '사전',   placeholder: '한문·산스크리트·빨리·티베트 용어 검색…' },
  { id: 'research',     kr: '연구',   placeholder: '연재·논고·개발일지 검색…' },
  { id: 'more',         kr: '더보기', placeholder: '색인·명상·안내 검색…' },
];

const HOME_TAB = { id: 'library', kr: '홈', placeholder: '경전·백과·용어 통합 검색…' };

const MORE_LINKS = [
  { id: 'meditate', kr: '명상', desc: '타이머·호흡 안내' },
  { id: 'explore',  kr: '색인', desc: '개념지도·연표·관계망' },
  { id: 'releases', kr: '개발 기록', desc: '릴리즈 노트·변경 이력' },
  { id: 'about',    kr: '안내', desc: '프로젝트·라이선스·로드맵' },
];

const MOBILE_GLOBAL_TABS = [
  { id: 'library',      kr: '홈',    icon: 'home' },
  { id: 'reader',       kr: '읽기',  icon: 'book' },
  { id: 'encyclopedia', kr: '백과',  icon: 'compass' },
  { id: 'dictionary',   kr: '사전',  icon: 'translate' },
  { id: 'research',     kr: '연구',  icon: 'pen' },
];

const MOBILE_READER_TABS = [
  { id: 'reading', kr: '읽기',  icon: 'book' },
  { id: 'dict',    kr: '사전',  icon: 'translate' },
  { id: 'connect', kr: '연결',  icon: 'link' },
  { id: 'note',    kr: '메모',  icon: 'note' },
  { id: 'search',  kr: '검색',  icon: 'search' },
];

/* ---------- App ---------- */
const App = () => {
  const [route, setRoute] = React.useState(() => {
    const x = location.hash.match(/x=([^&]+)/);
    if (x) return { name: 'reader', passageId: null, externalPath: decodeURIComponent(x[1]) };
    const h = location.hash.match(/p=([\w-]+)/);
    if (h) return { name: 'reader', passageId: h[1] };
    const r = location.hash.match(/r=(\w+)(?:\.([\w-]+))?/);
    if (r) return { name: r[1], id: r[2] || null };
    return { name: 'library' };
  });

  const [settings, setSettings] = React.useState(TWEAK_DEFAULTS);
  const [panel, setPanel] = React.useState(null);
  const [mode, setMode] = React.useState('parallel');
  const [bookmarks, setBookmarks] = React.useState([]);
  const [highlights] = React.useState([]);
  const [searchQuery, setSearchQuery] = React.useState('');
  const [searchResults, setSearchResults] = React.useState([]);
  const [ttsState, setTTSState] = React.useState({ playing: false, id: null });
  const [corpusState, setCorpusState] = React.useState({
    status: 'loading',
    manifest: null,
    error: null,
  });
  const [paliCatalogVersion, setPaliCatalogVersion] = React.useState(null);
  const [externalLoading, setExternalLoading] = React.useState(null);

  const [tweaksOpen, setTweaksOpen] = React.useState(false);
  React.useEffect(() => {
    const onMsg = (e) => {
      if (!e.data || typeof e.data !== 'object') return;
      if (e.data.type === '__activate_edit_mode') setTweaksOpen(true);
      if (e.data.type === '__deactivate_edit_mode') setTweaksOpen(false);
    };
    window.addEventListener('message', onMsg);
    window.parent.postMessage({type: '__edit_mode_available'}, '*');
    return () => window.removeEventListener('message', onMsg);
  }, []);
  const closeTweaks = () => {
    setTweaksOpen(false);
    window.parent.postMessage({type:'__edit_mode_dismissed'}, '*');
  };

  const [vw, setVW] = React.useState(window.innerWidth);
  React.useEffect(() => {
    const onR = () => setVW(window.innerWidth);
    window.addEventListener('resize', onR);
    return () => window.removeEventListener('resize', onR);
  }, []);
  const isMobile = vw < 768;

  React.useEffect(() => {
    let alive = true;
    window.CorpusClient.loadPaliCatalog()
      .then((catalog) => {
        window.CorpusClient.applyPaliCatalog(catalog);
        if (alive) setPaliCatalogVersion(catalog.version || catalog.generated_at || Date.now());
      })
      .catch((error) => {
        if (alive) setCorpusState((prev) => ({ ...prev, error }));
      });
    return () => { alive = false; };
  }, []);

  React.useEffect(() => {
    let alive = true;
    window.CorpusClient.loadManifest()
      .then((manifest) => {
        if (alive) setCorpusState({ status: 'ready', manifest, error: null });
      })
      .catch((error) => {
        if (alive) setCorpusState({ status: 'error', manifest: null, error });
      });
    return () => { alive = false; };
  }, []);

  /* ---------- 라우팅 헬퍼 ---------- */
  const goTo = (r) => {
    setRoute(r);
    if (r.name === 'reader' && r.externalPath) {
      history.replaceState(null, '', '#x=' + encodeURIComponent(r.externalPath));
    } else if (r.name === 'reader' && r.passageId) {
      history.replaceState(null, '', '#p=' + r.passageId);
    } else if (r.name === 'library') {
      history.replaceState(null, '', '#');
    } else {
      history.replaceState(null, '', '#r=' + r.name + (r.id ? '.' + r.id : ''));
    }
    window.scrollTo(0, 0);
  };
  const goHome = () => goTo({ name: 'library' });
  const firstReadablePassageId = () => (
    window.PALI_CATALOG?.groups?.[0]?.works?.[0]?.id || Object.keys(window.PASSAGES)[0]
  );
  const ensurePassageLoaded = async (id) => {
    if (!id || window.PASSAGES[id]) return true;
    const ref = window.PALI_PASSAGE_LOOKUP?.get(id);
    if (!ref) return false;
    setExternalLoading(id);
    try {
      const passage = await window.CorpusClient.loadPaliWork(ref.bucket, ref.workId);
      window.PASSAGES[passage.id || id] = passage;
      return true;
    } catch (error) {
      setCorpusState((prev) => ({ ...prev, error }));
      return false;
    } finally {
      setExternalLoading(null);
    }
  };
  const openPassage = async (id) => {
    if (!id) return;
    await ensurePassageLoaded(id);
    goTo({ name: 'reader', passageId: id });
  };
  const openCorpusPassage = async (ref) => {
    setExternalLoading(ref.path);
    try {
      const passage = await window.CorpusClient.loadPassage(ref, corpusState.manifest);
      window.PASSAGES[passage.id] = passage;
      goTo({ name: 'reader', passageId: passage.id, externalPath: ref.path });
    } catch (error) {
      setCorpusState((prev) => ({ ...prev, error }));
      alert('외부 본문을 불러오지 못했습니다. corpus 저장소 주소와 manifest를 확인해 주세요.');
    } finally {
      setExternalLoading(null);
    }
  };
  const openEncy = (id) => goTo({ name: 'encyclopedia', id });
  const openEncyCat = (catId) => goTo({ name: 'encyclopedia', cat: catId });
  const openDict = (id) => goTo({ name: 'dictionary', id });

  React.useEffect(() => {
    if (route.name !== 'reader' || !route.externalPath || route.passageId) return;
    let alive = true;
    setExternalLoading(route.externalPath);
    window.CorpusClient.loadPassage({ path: route.externalPath }, corpusState.manifest)
      .then((passage) => {
        if (!alive) return;
        window.PASSAGES[passage.id] = passage;
        setRoute((current) => (
          current.externalPath === route.externalPath
            ? { ...current, passageId: passage.id }
            : current
        ));
      })
      .catch((error) => {
        if (alive) setCorpusState((prev) => ({ ...prev, error }));
      })
      .finally(() => {
        if (alive) setExternalLoading(null);
      });
    return () => { alive = false; };
  }, [route.name, route.externalPath, route.passageId, corpusState.manifest]);

  React.useEffect(() => {
    if (route.name !== 'reader' || !route.passageId || window.PASSAGES[route.passageId]) return;
    if (!window.PALI_PASSAGE_LOOKUP?.has(route.passageId)) return;
    ensurePassageLoaded(route.passageId);
  }, [route.name, route.passageId, paliCatalogVersion]);

  const addBookmark = (p) => {
    if (bookmarks.find(b => b.passageId === route.passageId)) return;
    setBookmarks([{
      passageId: route.passageId, loc: p.head.kr,
      excerpt: (p.paragraphs[0]?.body || '').replace(/<[^>]+>/g,'').slice(0, 60) + '…',
      time: '방금'
    }, ...bookmarks]);
  };
  const jumpBookmark = (b) => openPassage(b.passageId);
  const doSearch = (q) => { setSearchQuery(q); setSearchResults(searchAll(q)); };
  const jumpSearch = (r) => openPassage(r.passageId);

  const toggleTTS = (id) => {
    if (ttsState.playing && ttsState.id === id) {
      try { speechSynthesis.cancel(); } catch (_) {}
      setTTSState({ playing: false, id: null }); return;
    }
    try { speechSynthesis.cancel(); } catch (_) {}
    const p = window.PASSAGES[id];
    const text = p.paragraphs.filter(x => !x.glyph).map(x => (x.body || '').replace(/<[^>]+>/g,'')).join(' ');
    if (!('speechSynthesis' in window)) return;
    const u = new SpeechSynthesisUtterance(text);
    u.lang = 'ko-KR'; u.rate = 0.92;
    u.onend = () => setTTSState({ playing: false, id: null });
    speechSynthesis.speak(u);
    setTTSState({ playing: true, id });
  };

  /* ---------- 검색 placeholder ---------- */
  const activeTab = NAV_TABS.find(t => t.id === route.name)
    || (route.name === 'library' ? HOME_TAB : null)
    || NAV_TABS[0];
  const searchPlaceholder = activeTab.placeholder;

  const [moreOpen, setMoreOpen] = React.useState(false);

  const handleHeaderTab = (tabId) => {
    setMoreOpen(false);
    if (tabId === 'more') { setMoreOpen(true); return; }
    if (tabId === 'reader') {
      const last = route.name === 'reader' ? route.passageId : firstReadablePassageId();
      openPassage(last);
    } else if (tabId === 'library') goHome();
    else goTo({ name: tabId });
  };

  const triggerSearch = () => {
    if (route.name === 'reader') { setPanel('search'); return; }
    if (route.name === 'encyclopedia' || route.name === 'dictionary') {
      /* 화면 내부 검색창에 포커스 */
      setTimeout(() => {
        const el = document.querySelector('[data-screen-search]');
        if (el) el.focus();
      }, 50);
      return;
    }
    /* fallback: 열람실 검색 */
    openPassage(firstReadablePassageId());
    setTimeout(() => setPanel('search'), 80);
  };

  const onMobileGlobalTab = (id) => {
    if (id === 'search') return triggerSearch();
    handleHeaderTab(id);
  };
  const onMobileReaderTab = (id) => {
    if (id === 'reading') { setPanel(null); return; }
    if (id === 'dict')    { setPanel('connect'); return; }
    if (id === 'connect') { setPanel('connect'); return; }
    if (id === 'note')    { setPanel('bookmarks'); return; }
    if (id === 'search')  { setPanel('search'); return; }
  };

  /* ---------- 헤더 ---------- */
  const Header = () => (
    <header className="site-header">
      <div className="site-header__inner">
        <button className="site-header__brand" onClick={goHome}>
          <span className="brand-main">삼장각</span>
          <span className="brand-sub">Dhamma Reader</span>
        </button>

        <div className="site-header__sep"/>

        <nav className="site-header__nav">
          {NAV_TABS.map(t => (
            <a key={t.id}
               className={(route.name === t.id || (t.id === 'more' && moreOpen)) ? 'is-active' : ''}
               onClick={() => handleHeaderTab(t.id)}>
              {t.kr}
            </a>
          ))}
        </nav>

        <div className="site-header__spacer"/>

        <button className="site-header__search-trigger" onClick={triggerSearch}>
          <AIcon name="search" size={16}/>
          <span>{searchPlaceholder}</span>
          <kbd>⌘K</kbd>
        </button>

        <button className="icon-btn site-header__icon-btn site-header__icon-btn-search" title="검색" onClick={triggerSearch}>
          <AIcon name="search" size={18}/>
        </button>
      </div>

      {moreOpen && (
        <div className="site-header__more-backdrop" onClick={() => setMoreOpen(false)}>
          <div className="site-header__more" onClick={(e) => e.stopPropagation()}>
            <div className="site-header__more-eyebrow">더보기 · MORE</div>
            <div className="site-header__more-list">
              {MORE_LINKS.map(m => (
                <button key={m.id} className="site-header__more-item"
                  onClick={() => { setMoreOpen(false); goTo({ name: m.id }); }}>
                  <div className="site-header__more-item-main">
                    <div className="site-header__more-item-kr">{m.kr}</div>
                    <div className="site-header__more-item-desc">{m.desc}</div>
                  </div>
                </button>
              ))}
            </div>
          </div>
        </div>
      )}
    </header>
  );

  /* ---------- 모바일 하단 탭 ---------- */
  const isReader = route.name === 'reader';
  const mobileTabs = isReader ? MOBILE_READER_TABS : MOBILE_GLOBAL_TABS;
  const mobileActive = isReader
    ? (panel === 'search' ? 'search'
       : panel === 'connect' ? 'connect'
       : panel === 'bookmarks' ? 'note'
       : 'reading')
    : route.name;
  const onMobileTab = isReader ? onMobileReaderTab : onMobileGlobalTab;

  return (
    <div className="app" data-route={route.name}>
      <Header/>

      {route.name === 'library' && (
        <window.Library
          onOpenPassage={openPassage}
          corpusState={corpusState}
          externalLoading={externalLoading}
          onOpenCorpusPassage={openCorpusPassage}
          onOpenEncy={openEncy}
          onOpenEncyCat={openEncyCat}
          onRoute={goTo}
        />
      )}

      {route.name === 'reader' && route.passageId && window.PASSAGES[route.passageId] && (
        <window.ReaderScreen
          passageId={route.passageId}
          onChangePassage={openPassage}
          onGoHome={goHome}
          settings={settings} onSettings={setSettings}
          panel={panel} onPanelChange={setPanel}
          mode={mode} onMode={setMode}
          bookmarks={bookmarks} onAddBookmark={addBookmark}
          onJumpBookmark={jumpBookmark}
          highlights={highlights} onJumpHighlight={jumpBookmark}
          searchResults={searchResults} searchQuery={searchQuery}
          onSearch={doSearch} onJumpSearch={jumpSearch}
          ttsState={ttsState} onTTS={toggleTTS}
          isMobile={isMobile}
          onOpenEncy={openEncy} onOpenDict={openDict}
        />
      )}

      {route.name === 'reader' && (!route.passageId || !window.PASSAGES[route.passageId]) && (
        <div style={{padding:60, textAlign:'center', color:'var(--ink-mute)'}}>
          {externalLoading ? '본문을 불러오는 중입니다.' : '본문을 불러올 수 없습니다.'}
        </div>
      )}

      {route.name === 'encyclopedia' && (
        <window.Encyclopedia
          entryId={route.id} catId={route.cat}
          onOpenEntry={openEncy}
          onOpenPassage={openPassage}
          onOpenDict={openDict}
          onRoute={goTo}
        />
      )}

      {route.name === 'dictionary' && (
        <window.Dictionary
          entryId={route.id}
          onOpen={openDict}
          onOpenEncy={openEncy}
          onRoute={goTo}
        />
      )}

      {route.name === 'explore' && (
        <window.Explore onOpenEncy={openEncy} onOpenPassage={openPassage} onRoute={goTo}/>
      )}

      {route.name === 'research' && (
        <window.Research onRoute={goTo}/>
      )}

      {route.name === 'releases' && (
        <window.ReleaseNotes onRoute={goTo}/>
      )}

      {route.name === 'about' && (
        <window.About onRoute={goTo}/>
      )}

      {route.name === 'meditate' && (
        <window.Meditate onGoHome={goHome}/>
      )}

      <TweaksFloat open={tweaksOpen} onClose={closeTweaks} settings={settings} setSettings={setSettings}/>

      {/* 모바일 하단 탭 */}
      <nav className={"mobile-tabbar" + (isReader ? ' is-reader' : '')}>
        {mobileTabs.map(t => (
          <button key={t.id}
                  className={'mobile-tabbar__btn' + (mobileActive === t.id ? ' is-active' : '')}
                  onClick={() => onMobileTab(t.id)}>
            <AIcon name={t.icon} size={20}/>
            <span>{t.kr}</span>
          </button>
        ))}
      </nav>
    </div>
  );
};

ReactDOM.createRoot(document.getElementById('root')).render(<App/>);
