<?php
declare(strict_types=1);
/**
 * 사용자 매뉴얼 뷰.
 *
 * @var array<string, array{title:string,file:string}> $pages  목차
 * @var string $current  현재 slug
 * @var string $title    현재 페이지 제목
 * @var string $body     commonmark 로 변환된 HTML (신뢰된 콘텐츠)
 */
$pages   = $pages ?? [];
$current = (string) ($current ?? '');
$title   = (string) ($title ?? '사용자 매뉴얼');
$body    = (string) ($body ?? '');

$slugs    = array_keys($pages);
$pos      = array_search($current, $slugs, true);
$prevSlug = ($pos !== false && $pos > 0) ? $slugs[$pos - 1] : null;
$nextSlug = ($pos !== false && $pos < count($slugs) - 1) ? $slugs[$pos + 1] : null;
$searchQ  = (string) (service('request')->getGet('q') ?? '');
?>
<style>
/* 매뉴얼 본문 스코프 스타일 (사이트 레이아웃 Tailwind 에 typography 플러그인 없음) */
.manual-prose { color: #1f2937; font-size: 0.95rem; line-height: 1.75; max-width: 52rem; }
.manual-prose h1 { font-size: 1.6rem; font-weight: 800; margin: 0 0 1rem; color: #111827; }
.manual-prose h2 { font-size: 1.25rem; font-weight: 700; margin: 1.8rem 0 0.7rem; padding-bottom: 0.35rem; border-bottom: 2px solid #e5e7eb; color: #1d4ed8; scroll-margin-top: 1rem; }
.manual-prose h3 { font-size: 1.05rem; font-weight: 700; margin: 1.3rem 0 0.5rem; color: #374151; }
.manual-prose p { margin: 0.6rem 0; }
.manual-prose ul, .manual-prose ol { margin: 0.6rem 0 0.6rem 1.4rem; }
.manual-prose ul { list-style: disc; }
.manual-prose ol { list-style: decimal; }
.manual-prose li { margin: 0.25rem 0; }
.manual-prose li > ul, .manual-prose li > ol { margin-top: 0.25rem; }
.manual-prose a { color: #1a2b4b; text-decoration: underline; }
.manual-prose a:hover { color: #2563eb; }
.manual-prose strong { font-weight: 700; color: #111827; }
.manual-prose blockquote { margin: 0.9rem 0; padding: 0.6rem 1rem; border-left: 4px solid #60a5fa; background: #eff6ff; color: #1e3a8a; border-radius: 0 6px 6px 0; }
.manual-prose code { background: #f3f4f6; color: #b91c1c; padding: 0.1rem 0.35rem; border-radius: 4px; font-size: 0.85em; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
.manual-prose pre { background: #1e293b; color: #e2e8f0; padding: 0.9rem 1rem; border-radius: 8px; overflow-x: auto; margin: 0.9rem 0; font-size: 0.85rem; line-height: 1.6; }
.manual-prose pre code { background: transparent; color: inherit; padding: 0; }
.manual-prose table { border-collapse: collapse; width: 100%; margin: 1rem 0; font-size: 0.875rem; }
.manual-prose th, .manual-prose td { border: 1px solid #d1d5db; padding: 0.45rem 0.7rem; text-align: left; vertical-align: top; }
.manual-prose th { background: #e9ecef; font-weight: 700; color: #333; }
.manual-prose tbody tr:nth-child(even) td { background: #f9fafb; }
.manual-prose hr { margin: 1.6rem 0; border: 0; border-top: 1px solid #e5e7eb; }
.manual-toc a.active { background: #1a2b4b; color: #fff; font-weight: 700; }
/* 소제목 옆 "화면 열기" 바로가기 */
.manual-jump { display: inline-flex; align-items: center; gap: 4px; margin-left: 8px; vertical-align: middle; font-size: 0.72rem; font-weight: 700; color: #1d4ed8; background: #eff6ff; border: 1px solid #bfdbfe; border-radius: 9999px; padding: 2px 9px; text-decoration: none; cursor: pointer; white-space: nowrap; }
.manual-jump:hover { background: #1d4ed8; color: #fff; border-color: #1d4ed8; }
.manual-jump i { font-size: 0.65rem; }
/* "이 화면 설명"으로 들어왔을 때 해당 소제목 강조 */
.manual-prose h2.hl-flash, .manual-prose h3.hl-flash { background: #fef9c3; box-shadow: -6px 0 0 #fef9c3, 6px 0 0 #fef9c3; border-radius: 4px; animation: hlFlash 2.6s ease-out 1; }
@keyframes hlFlash { 0%, 45% { background: #fde047; box-shadow: -6px 0 0 #fde047, 6px 0 0 #fde047; } 100% { background: transparent; box-shadow: -6px 0 0 transparent, 6px 0 0 transparent; } }
@media print {
  .manual-toc, .manual-actions, .manual-nav, .manual-jump { display: none !important; }
  .manual-layout { display: block !important; }
  .manual-prose { max-width: none; }
}
</style>

<div class="manual-layout flex gap-6 items-start max-w-6xl mx-auto">
  <!-- 좌측 목차 -->
  <nav class="manual-toc no-print w-56 shrink-0 sticky top-0 self-start">
    <div class="bg-title-bar text-white text-sm font-bold px-3 py-2 rounded-t">사용자 매뉴얼</div>
    <!-- 매뉴얼 전체 검색 -->
    <div class="manual-search" style="position:relative;padding:6px;border:1px solid #d1d5db;border-top:0;background:#fff;">
      <div style="position:relative;">
        <input id="manualSearchInput" type="search" autocomplete="off" placeholder="매뉴얼 검색 (예: LOT, 불출)"
               value="<?= esc($searchQ, 'attr') ?>"
               class="w-full border border-gray-300 rounded px-2 py-1.5 pr-7 text-xs focus:outline-none focus:ring-2 focus:ring-[#243a5e]/30"/>
        <i class="fa-solid fa-magnifying-glass" style="position:absolute;right:8px;top:50%;transform:translateY(-50%);color:#9ca3af;font-size:11px;"></i>
      </div>
      <ul id="manualSearchResults" class="hidden" style="position:absolute;left:6px;right:6px;top:100%;z-index:40;max-height:300px;overflow-y:auto;background:#fff;border:1px solid #d1d5db;border-radius:6px;box-shadow:0 6px 16px rgba(0,0,0,.12);margin:2px 0 0;padding:0;list-style:none;"></ul>
    </div>
    <ul class="border border-t-0 border-gray-300 rounded-b divide-y divide-gray-100 bg-white text-sm">
      <?php foreach ($pages as $slug => $p): ?>
      <li>
        <a href="<?= base_url('bag/manual/' . $slug) ?>"
           class="block px-3 py-2 text-gray-700 hover:bg-blue-50 <?= $slug === $current ? 'active' : '' ?>">
          <?= esc($p['title']) ?>
        </a>
      </li>
      <?php endforeach; ?>
    </ul>
  </nav>

  <!-- 본문 -->
  <div class="flex-grow min-w-0">
    <div class="manual-actions no-print flex justify-end mb-3">
      <button type="button" onclick="window.print()"
              class="text-sm border border-gray-300 rounded px-3 py-1.5 text-gray-600 hover:bg-gray-50">
        인쇄
      </button>
    </div>

    <article class="manual-prose"><?= $body ?></article>

    <!-- 이전/다음 -->
    <div class="manual-nav no-print flex justify-between mt-8 pt-4 border-t border-gray-200 text-sm">
      <?php if ($prevSlug !== null): ?>
      <a href="<?= base_url('bag/manual/' . $prevSlug) ?>" class="text-blue-700 hover:underline">&larr; <?= esc($pages[$prevSlug]['title']) ?></a>
      <?php else: ?>
      <span></span>
      <?php endif; ?>
      <?php if ($nextSlug !== null): ?>
      <a href="<?= base_url('bag/manual/' . $nextSlug) ?>" class="text-blue-700 hover:underline"><?= esc($pages[$nextSlug]['title']) ?> &rarr;</a>
      <?php endif; ?>
    </div>
  </div>
</div>

<script>
(function () {
  // 현재 출처 기준 경로(앱 baseURL 호스트와 접속 호스트가 달라도 동일 출처로 요청)
  var SEARCH_URL = location.origin + <?= json_encode((string) parse_url(base_url('bag/manual/search'), PHP_URL_PATH), JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT) ?>;
  var BASE = location.origin + <?= json_encode((string) parse_url(base_url('bag/manual/'), PHP_URL_PATH), JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT) ?>;
  var Q0 = <?= json_encode($searchQ, JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS) ?>;
  // 이 매뉴얼 페이지가 설명하는 화면 바로가기 목록 [{hint, url}, ...]
  var JUMPS = <?= json_encode($jumps ?? [], JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS) ?>;
  // "이 화면 설명"으로 들어온 경우: 해당 소제목으로 스크롤 + 강조.
  // 드로어를 껐다 다시 켜도(같은 URL이라 iframe 재로드 안 됨) 부모가 보낸 메시지로 다시 강조한다.
  var hlFlashTimer = null;
  function runHl() {
    var hl = '';
    try { hl = new URLSearchParams(location.search).get('hl') || ''; } catch (e) {}
    hl = hl.trim();
    if (!hl) return;
    var norm = function (s) { return String(s || '').replace(/\s+/g, ' ').trim().toLowerCase(); };
    var needle = norm(hl);
    var prose = document.querySelector('.manual-prose');
    if (!prose) return;
    var heads = prose.querySelectorAll('h2, h3'), target = null;
    for (var i = 0; i < heads.length; i++) {
      if (norm(heads[i].textContent).indexOf(needle) >= 0) { target = heads[i]; break; }
    }
    if (!target) return;
    clearTimeout(hlFlashTimer);
    target.classList.remove('hl-flash');
    void target.offsetWidth; // 리플로우 → 애니메이션 재시작
    target.classList.add('hl-flash');
    try { target.scrollIntoView({ block: 'start', behavior: 'smooth' }); } catch (e) { target.scrollIntoView(); }
    hlFlashTimer = setTimeout(function () { target.classList.remove('hl-flash'); }, 2700);
  }
  runHl();
  window.addEventListener('message', function (e) {
    if (e.origin !== location.origin) return;
    if (e.data && e.data.type === 'manual-hl') runHl();
  });

  // 해당 화면으로 이동: 워크스페이스(탭) 안이면 새 탭으로, 아니면 최상위 창을 이동.
  function openScreen(url, title) {
    try { if (window.top && typeof window.top.wsOpenTab === 'function') { window.top.wsOpenTab(url, title); return; } } catch (e) {}
    try { if (window.parent && typeof window.parent.wsOpenTab === 'function') { window.parent.wsOpenTab(url, title); return; } } catch (e) {}
    try { window.top.location.href = url; } catch (e) { window.location.href = url; }
  }
  // 각 소제목(h2/h3) 옆에 "화면 열기" 바로가기 버튼을 붙인다(hint 매칭).
  (function attachJumps() {
    if (!JUMPS || !JUMPS.length) return;
    var prose = document.querySelector('.manual-prose');
    if (!prose) return;
    var norm = function (s) { return String(s || '').replace(/\s+/g, ' ').trim().toLowerCase(); };
    var heads = prose.querySelectorAll('h2, h3');
    JUMPS.forEach(function (j) {
      var needle = norm(j.hint);
      if (!needle || !j.url) return;
      for (var i = 0; i < heads.length; i++) {
        var h = heads[i];
        if (h.getAttribute('data-jump')) continue; // 한 제목엔 하나만
        if (norm(h.textContent).indexOf(needle) < 0) continue;
        var label = (h.textContent || '화면').trim(); // 버튼 추가 전 제목 확보
        var url = j.url;
        var a = document.createElement('a');
        a.className = 'manual-jump';
        a.href = url;
        a.title = '이 화면으로 이동';
        a.innerHTML = '<i class="fa-solid fa-arrow-up-right-from-square"></i> 화면 열기';
        a.addEventListener('click', function (ev) { ev.preventDefault(); openScreen(url, label); });
        h.appendChild(a);
        h.setAttribute('data-jump', '1');
        break;
      }
    });
  })();
  var input = document.getElementById('manualSearchInput');
  var box = document.getElementById('manualSearchResults');

  function esc(s) { return String(s || '').replace(/[&<>]/g, function (c) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;' }[c]; }); }

  function doSearch(q) {
    q = (q || '').trim();
    if (!q) { box.classList.add('hidden'); box.innerHTML = ''; return; }
    fetch(SEARCH_URL + '?q=' + encodeURIComponent(q))
      .then(function (r) { return r.json(); })
      .then(function (d) {
        var res = (d && d.results) || [];
        if (!res.length) {
          box.innerHTML = '<li style="padding:7px 10px;color:#9ca3af;font-size:12px;">검색 결과가 없습니다.</li>';
          box.classList.remove('hidden'); return;
        }
        box.innerHTML = res.map(function (m) {
          return '<li><a href="' + BASE + encodeURIComponent(m.slug) + '?q=' + encodeURIComponent(q) +
            '" style="display:block;padding:7px 10px;border-bottom:1px solid #f1f5f9;text-decoration:none;">' +
            '<span style="font-size:12px;font-weight:700;color:#1a2b4b;">' + esc(m.title) +
            ' <span style="color:#94a3b8;font-weight:400;">(' + (m.hits || 1) + ')</span></span>' +
            '<span style="display:block;font-size:11px;color:#64748b;margin-top:2px;line-height:1.4;">' + esc(m.snippet) + '</span></a></li>';
        }).join('');
        box.classList.remove('hidden');
      })
      .catch(function () {});
  }

  if (input) {
    var timer = null;
    input.addEventListener('input', function () { clearTimeout(timer); var v = input.value; timer = setTimeout(function () { doSearch(v); }, 250); });
    input.addEventListener('focus', function () { if (input.value.trim()) doSearch(input.value); });
    document.addEventListener('click', function (e) { if (!e.target.closest('.manual-search')) box.classList.add('hidden'); });
  }

  // 현재 페이지 본문에서 검색어 하이라이트
  if (Q0 && Q0.trim()) {
    var prose = document.querySelector('.manual-prose');
    if (prose) {
      var needle = Q0.trim().toLowerCase();
      var walker = document.createTreeWalker(prose, NodeFilter.SHOW_TEXT, null);
      var nodes = [], first = null;
      while (walker.nextNode()) { nodes.push(walker.currentNode); }
      nodes.forEach(function (node) {
        var t = node.nodeValue, lt = t.toLowerCase(), idx = lt.indexOf(needle);
        if (idx < 0) return;
        var frag = document.createDocumentFragment(), last = 0;
        while (idx >= 0) {
          frag.appendChild(document.createTextNode(t.slice(last, idx)));
          var mark = document.createElement('mark');
          mark.textContent = t.slice(idx, idx + needle.length);
          mark.style.background = '#fde68a';
          frag.appendChild(mark);
          if (!first) first = mark;
          last = idx + needle.length;
          idx = lt.indexOf(needle, last);
        }
        frag.appendChild(document.createTextNode(t.slice(last)));
        node.parentNode.replaceChild(frag, node);
      });
      if (first) { try { first.scrollIntoView({ block: 'center' }); } catch (e) {} }
    }
  }
})();
</script>
