/* global React */
const { useState: useStateF, useEffect: useEffectF } = React;
const { describeItem, FlowDiagram } = window.LGFeatureData;

// ===== Core Feature Architecture =====
// 10 categories, accordion-style, with platform tags
function Features() {
  const cats = [
    {
      idx: '01',
      title: '核心系統功能',
      en: 'Core System',
      blurb: '從檢傷分類、語音回報、命令廣播到節點監控與離線備份 —— 災區現場到指揮中心的完整指揮鏈。',
      platforms: ['iOS', 'Android', 'macOS', 'Windows', 'Web'],
      groups: [
        {
          name: 'AI 指揮與檢傷',
          items: ['AI 災害救援指揮決策', 'START 傷患檢傷分類', '傷患資料回報', '語音回報 / PTT 電台', '語音轉文字', 'GPS 位置回報'],
        },
        {
          name: '命令與任務',
          items: ['多裝置即時同步', '指揮命令廣播', '任務指派與進度回報', '災害狀態管理', '人員配置管理', '增援請求與回覆'],
        },
        {
          name: '警報與標記',
          items: ['SOS 求救警報', '危險標記回報', '即時氣象資料整合'],
        },
        {
          name: 'LoRa 與資料層',
          items: ['LoRa 節點監控', 'BLE 連接 LoRa 節點', 'MQTT 節點狀態聚合', 'Bonjour / mDNS 自動服務發現', '離線備份與 USB 備份', '事件日誌與歷史紀錄'],
        },
        {
          name: '介面',
          items: ['Web Dashboard', '夜視儀風格深色介面'],
        },
      ],
    },
    {
      idx: '02',
      title: 'AI / 後端功能',
      en: 'AI & Backend',
      blurb: '雙模型 AI 決策架構：小模型快速初判、大模型深度分析；本機 Ollama 推論不依賴雲端。',
      platforms: ['Python', 'Ollama', 'SQLite'],
      groups: [
        {
          name: '決策引擎',
          items: ['AI 指揮決策生成', '雙模型 AI 決策架構', '小模型快速初判', '大模型深度分析', '信心度不足時自動升級', 'Ollama 本機模型推論'],
        },
        {
          name: '檢傷與翻譯',
          items: ['START 三步驟檢傷', '六維度加權評分', '傷患優先順序排序', '醫療翻譯 API', '語音轉錄 API'],
        },
        {
          name: '紀錄與資料',
          items: ['會報摘要生成', '歷史決策記錄', '氣象資料格式化給 AI', '傷患摘要格式化給 AI', 'SQLite 統一資料庫', '系統事件記錄', '離線回放資料支援'],
        },
      ],
    },
    {
      idx: '03',
      title: 'Python / Windows 後端服務',
      en: 'Backend Services',
      blurb: '十支微服務各司其職 —— TCP 指揮、UDP 語音、AI 推論、Whisper 轉錄、HTTP API、照片、統計、資源、MQTT、PWS、USB 備份、離線回放。',
      platforms: ['Python', 'FastAPI', 'Windows'],
      groups: [
        {
          name: 'tcp_server',
          items: ['接收前線訊息', '訊息聚合', 'AI 決策觸發', '決策廣播', '傷患 / 位置 / 語音 / PTT / 文字廣播中繼'],
        },
        {
          name: 'gemma4_server / qwen_server',
          items: ['AI 決策生成', '模型切換', '翻譯', '雙模型升級'],
        },
        {
          name: 'whisper_server',
          items: ['Whisper 語音辨識', '音訊上傳轉文字'],
        },
        {
          name: 'http_server',
          items: ['會報上傳', '音訊檔案回放', 'Web Dashboard'],
        },
        {
          name: 'photo_server',
          items: ['照片上傳', '原圖取得', '縮圖生成', '照片警報推播'],
        },
        {
          name: 'stats_server',
          items: ['即時統計', '歷史統計'],
        },
        {
          name: 'resource_server',
          items: ['資源 CRUD', '資源部署', '資源回收'],
        },
        {
          name: 'udp_server',
          items: ['低延遲語音廣播接收', '音訊封包去重', 'PCM 轉 WAV', '送 Whisper 轉錄'],
        },
        {
          name: 'mqtt_broker',
          items: ['LoRa 節點狀態訂閱', 'RSSI / SNR / 電量 / GPS / PDR 更新'],
        },
        {
          name: 'pws_fetcher · usb_backup · replay',
          items: ['中央氣象署資料抓取', '本機備份', 'USB 同步', '定時完整備份', '離線事件回放', '指定時間快照', '決策 / 傷患 / 位置 / 會報 / 節點紀錄查詢'],
        },
      ],
    },
    {
      idx: '04',
      title: 'iOS / iPadOS 前線 App',
      en: 'iOS Field App',
      blurb: '搜救員手上的指揮儀 —— 從 PTT 電台、傷員回報到 SOS 全螢幕警報，皆可在 BLE LoRa 與 WiFi HQ 雙連線下作業。',
      platforms: ['iOS', 'iPadOS', 'SwiftUI'],
      groups: [
        {
          name: 'Dashboard 與通訊',
          items: ['總覽 Dashboard', '電台 / PTT', '通訊聊天', '指揮決策接收', '災情顯示', 'SOS 記錄', '受困者列表', '增援請求'],
        },
        {
          name: '團隊與任務',
          items: ['團隊狀態', '命令接收', '通知中心', '傷員回報表單', '翻譯', '照片上傳', '連線狀態', '快速狀態回報', '倒數計時器', '待處理任務', '危險標記'],
        },
        {
          name: '警報與輔助',
          items: ['交班摘要生成', 'Critical 命令全螢幕提醒', 'SOS 全螢幕警報', '增援請求覆蓋提醒'],
        },
        {
          name: '連線',
          items: ['BLE LoRa 連線', 'WiFi HQ 連線', '模擬模式', '夜視儀 UI 主題'],
        },
      ],
    },
    {
      idx: '05',
      title: 'Android Rescue 前線 App',
      en: 'Android Field App',
      blurb: '響應式手機 / 平板介面，覆蓋 iOS 端所有外勤功能，並可作為備援裝置。',
      platforms: ['Android', 'Kotlin', 'Compose'],
      groups: [
        {
          name: '九大頁面',
          items: ['響應式手機 / 平板介面', '總覽', '受困者', 'SOS', '災情', '通訊', '增援', '團隊', '命令', '通知'],
        },
        {
          name: '功能',
          items: ['電台 PTT', '傷員回報', 'AI 決策接收', '翻譯', '照片功能'],
        },
        {
          name: '連線與服務',
          items: ['連線設定', 'HQ 自動探索 / NSD', 'BLE 連接 LoRa', '模擬引擎', '警報播放', '通知管理'],
        },
      ],
    },
    {
      idx: '06',
      title: 'macOS HQ 指揮中心',
      en: 'macOS HQ',
      blurb: '指揮官的主戰情台 —— 全螢幕 Dashboard、會報儀表板、AI 建議、廣播控制；可獨立於 Windows 後端 Mac-only 運作。',
      platforms: ['macOS', 'SwiftUI'],
      groups: [
        {
          name: 'Dashboard',
          items: ['指揮中心 Dashboard', '災害狀態管理', '人員總覽', '受困者總覽', '人員配置', '通訊頻道', 'PWS 警報', '會報系統', '個人通知', '事件日誌', '分區地圖', '會報儀表板'],
        },
        {
          name: '指揮與分發',
          items: ['指揮決策', '照片牆', '統計儀表板', '資源管理', '傷員警告', 'AI 聊天 / AI 建議卡', '廣播功能', '電台監聽 / 音訊中繼', 'HQ Peer 同步', '指定裝置群發命令', 'Broadcast 全體命令'],
        },
        {
          name: '橋接與獨立模式',
          items: ['與 Windows 後端橋接', 'Mac-only 獨立模式', '本地 Apple Speech 語音辨識', '本地照片伺服器', '本地統計計算', '本地資源計算', '翻譯離線 fallback'],
        },
      ],
    },
    {
      idx: '07',
      title: 'Android HQ 指揮中心',
      en: 'Android HQ',
      blurb: '行動式 HQ 終端 —— 平板優先、手機可用，內建 TCP Server / Backend Bridge / Peer Client，支援命令下達與外勤管理。',
      platforms: ['Android', 'Kotlin'],
      groups: [
        {
          name: '主控台',
          items: ['HQ Dashboard', '命令下達', '外勤裝置列表', '人員總覽', '受困者列表', '災情管理', '通訊', '人員配置', 'PWS 警報', '會報', '通知', '傷員回報', '指揮決策', '事件日誌', '分區地圖', '會報儀表板'],
        },
        {
          name: '伺服與橋接',
          items: ['HQ TCP Server', 'HQ Backend Bridge', 'HQ Peer Client', 'Android 本地語音伺服器', 'Android HQ 音訊串流伺服器'],
        },
        {
          name: '裝置管理',
          items: ['BLE 管理', '指定裝置選擇器', '平板 / 手機響應式介面'],
        },
      ],
    },
    {
      idx: '08',
      title: 'Web Dashboard',
      en: 'Web Dashboard',
      blurb: '瀏覽器即可進入的總覽介面 —— 即時統計、照片牆、PDF 報告、自訂後台 IP。',
      platforms: ['Web', 'FastAPI'],
      groups: [
        {
          name: '統計與資料',
          items: ['即時統計', '傷患分類統計', '人員統計', '資源概況', '通訊狀態', '資源管理'],
        },
        {
          name: '紀錄與報告',
          items: ['照片牆', '會報紀錄', 'PDF 報告生成', '事件歷史'],
        },
        {
          name: '介面',
          items: ['可自訂後台 IP', '夜視儀暗色主題'],
        },
      ],
    },
    {
      idx: '09',
      title: '通訊與資料協定',
      en: 'Network Protocols',
      blurb: '多協定混合架構 —— TCP 指揮、UDP/LGAP 語音、MQTT 節點狀態、HTTP API、Bonjour 自動發現、HQ Peer 同步。',
      platforms: ['TCP', 'UDP', 'MQTT', 'HTTP'],
      groups: [
        {
          name: '通訊協定',
          items: ['TCP 指揮通訊', 'UDP 語音廣播', 'LGAP 音訊串流', 'MQTT LoRa 節點狀態', 'HTTP API', 'FastAPI 後端服務'],
        },
        {
          name: '同步與發現',
          items: ['Bonjour / NSD 自動發現', 'HQ Peer 同步', 'Field ↔ HQ 雙向訊息', 'HQ ↔ Backend 橋接'],
        },
        {
          name: '訊息控制',
          items: ['多裝置廣播', '指定裝置推播', '訊息 ACK', 'Ping / Pong 心跳'],
        },
      ],
    },
    {
      idx: '10',
      title: '資料管理',
      en: 'Data Management',
      blurb: '所有資料以 SQLite WAL 模式統一儲存，可 USB 備份與離線回放，支援事後檢討與資料追溯。',
      platforms: ['SQLite', 'WAL', 'USB'],
      groups: [
        {
          name: '紀錄類型',
          items: ['決策記錄', '傷患資料', 'GPS 軌跡', '會報紀錄', '氣象歷史', '語音轉錄紀錄', 'LoRa 節點狀態歷史', '系統事件', '照片紀錄', '音訊檔案保存'],
        },
        {
          name: '儲存與備援',
          items: ['SQLite WAL 模式', 'USB 備份', '離線回放資料輸出'],
        },
      ],
    },
  ];

  // first item open by default
  const [openIdx, setOpenIdx] = useStateF(0);
  const [modal, setModal] = useStateF(null); // {kind:'item'|'group', name, group, cat}

  const openItem = (name, group, cat) => setModal({ kind: 'item', name, group, cat });
  const openGroup = (group, cat) => setModal({ kind: 'group', group, cat });

  // total count for header
  const total = cats.reduce((acc, c) => acc + c.groups.reduce((a, g) => a + g.items.length, 0), 0);

  return (
    <section id="features">
      <div className="container">
        <div className="section-head">
          <div className="meta">
            <span className="label">[ 02.5 ]</span>
            <span className="label">/ 核心功能架構</span>
          </div>
          <h2 className="h2 reveal">
            十大功能群、{total} 項功能、<br />
            一套指揮鏈閉環。
          </h2>
        </div>

        <div className="features-intro reveal">
          <p>
            LinkGuard 並非單一裝置，而是<span className="key">前線、指揮中心、後端</span>三層的軟硬整合系統。
            從外勤手機 / 平板回報，到 HQ 即時統計與 AI 決策，再到後端微服務群與離線備份 ——
            每一條訊號都在閉環內被記錄、分析與歸檔。
          </p>
        </div>

        <div className="features-acc reveal-stagger">
          {cats.map((c, i) => {
            const open = openIdx === i;
            const totalC = c.groups.reduce((a, g) => a + g.items.length, 0);
            return (
              <div key={c.idx} className={'feat-row' + (open ? ' open' : '')}>
                <button
                  type="button"
                  className="feat-head"
                  onClick={() => setOpenIdx(open ? -1 : i)}
                  data-hover
                >
                  <span className="feat-idx">{c.idx}</span>
                  <div className="feat-title-block">
                    <div className="feat-title">
                      <span className="zh">{c.title}</span>
                      <span className="feat-en">{c.en}</span>
                    </div>
                    <div className="feat-blurb">{c.blurb}</div>
                  </div>
                  <div className="feat-meta">
                    <div className="feat-tags">
                      {c.platforms.map((p) => <span key={p} className="feat-tag">{p}</span>)}
                    </div>
                    <div className="feat-count">
                      <span className="n">{totalC}</span>
                      <span className="u">項</span>
                    </div>
                  </div>
                  <span className="feat-toggle" aria-hidden>
                    <svg viewBox="0 0 14 14" width="14" height="14"><path d="M2 7 L12 7 M7 2 L7 12" stroke="currentColor" strokeWidth="1.2" /></svg>
                  </span>
                </button>

                <div className="feat-body">
                  <div className="feat-body-inner">
                    {c.groups.map((g) => (
                      <div key={g.name} className="feat-group">
                        <button type="button" className="feat-group-name feat-group-btn" onClick={() => openGroup(g, c)} data-hover>
                          <span className="dot" />
                          <span>{g.name}</span>
                          <span className="ct">{g.items.length}</span>
                          <span className="feat-group-arrow" aria-hidden>↗</span>
                        </button>
                        <ul className="feat-items">
                          {g.items.map((it) => (
                            <li key={it}>
                              <button type="button" className="feat-item-btn" onClick={(e) => { e.stopPropagation(); openItem(it, g, c); }} data-hover>
                                <span className="bullet">▸</span>
                                <span className="label">{it}</span>
                                <span className="feat-item-arrow" aria-hidden>↗</span>
                              </button>
                            </li>
                          ))}
                        </ul>
                      </div>
                    ))}
                  </div>
                </div>
              </div>
            );
          })}
        </div>
      </div>
      <FeatureModal modal={modal} onClose={() => setModal(null)} />
    </section>
  );
}

// ===== Feature Modal =====
function FeatureModal({ modal, onClose }) {
  // ESC + lock body scroll
  useEffectF(() => {
    if (!modal) return;
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', onKey);
    const prev = document.body.style.overflow;
    document.body.style.overflow = 'hidden';
    return () => {
      window.removeEventListener('keydown', onKey);
      document.body.style.overflow = prev;
    };
  }, [modal, onClose]);

  if (!modal) return null;

  const { kind, cat, group } = modal;
  const isItem = kind === 'item';
  const title = isItem ? modal.name : group.name;
  const breadcrumb = isItem
    ? `${cat.idx} ${cat.title} / ${group.name}`
    : `${cat.idx} ${cat.title}`;

  // Build content
  let info;
  if (isItem) {
    info = describeItem(modal.name, group.name, cat);
  } else {
    info = {
      desc: `「${group.name}」是 ${cat.title} 之下的一個子模組，包含 ${group.items.length} 項小功能。下方列出全部小功能與其在系統中的角色，可點擊任一項查看更詳細的技術說明。`,
      proto: cat.platforms,
    };
  }

  return (
    <div className="fm-overlay" onClick={onClose} role="dialog" aria-modal="true">
      <div className="fm-panel" onClick={(e) => e.stopPropagation()}>
        <div className="fm-head">
          <div className="fm-crumb">
            <span className="fm-idx">{cat.idx}</span>
            <span>{breadcrumb}</span>
          </div>
          <button type="button" className="fm-close" onClick={onClose} aria-label="關閉" data-hover>
            <svg viewBox="0 0 14 14" width="14" height="14"><path d="M2 2 L12 12 M12 2 L2 12" stroke="currentColor" strokeWidth="1.4" /></svg>
          </button>
        </div>

        <div className="fm-body">
          <div className="fm-title-row">
            <h3 className="fm-title">{title}</h3>
            <div className="fm-tags">
              {(info.proto || []).map((p) => <span key={p} className="fm-tag">{p}</span>)}
            </div>
          </div>

          <div className="fm-grid">
            <div className="fm-col-main">
              <div className="fm-section">
                <div className="fm-section-name">概述</div>
                <p className="fm-desc">{info.desc}</p>
              </div>

              {!isItem && (
                <div className="fm-section">
                  <div className="fm-section-name">包含項目（{group.items.length}）</div>
                  <ul className="fm-items">
                    {group.items.map((it) => <li key={it}><span className="b">▸</span>{it}</li>)}
                  </ul>
                </div>
              )}
            </div>

            <div className="fm-col-side">
              <div className="fm-section">
                <div className="fm-section-name">所屬模組</div>
                <div className="fm-stat">
                  <div className="fm-stat-key">分類</div>
                  <div className="fm-stat-val">{cat.title}</div>
                </div>
                <div className="fm-stat">
                  <div className="fm-stat-key">子分類</div>
                  <div className="fm-stat-val">{group.name}</div>
                </div>
                {isItem && (
                  <div className="fm-stat">
                    <div className="fm-stat-key">類型</div>
                    <div className="fm-stat-val">小功能</div>
                  </div>
                )}
              </div>

              <div className="fm-section">
                <div className="fm-section-name">平台 / 模組</div>
                <div className="fm-tags">
                  {cat.platforms.map((p) => <span key={p} className="fm-tag">{p}</span>)}
                </div>
              </div>

              <div className="fm-section">
                <div className="fm-section-name">介面示意</div>
                <ScreenshotSlot modal={modal} />
              </div>
            </div>
          </div>
        </div>

        <div className="fm-foot">
          <span className="fm-foot-label">ESC 關閉</span>
          <span className="fm-foot-mono">REF · {cat.idx}.{(group && cat.groups.indexOf(group) + 1) || 0}{isItem ? `.${group.items.indexOf(modal.name) + 1}` : ''}</span>
        </div>
      </div>
    </div>
  );
}

// ===== Screenshot slot — auto-resolve image path with placeholder fallback =====
function ScreenshotSlot({ modal }) {
  const { cat, group, kind } = modal;
  const groupIdx = cat.groups.indexOf(group) + 1;
  const pad = (n) => String(n).padStart(2, '0');
  let path;
  if (kind === 'item') {
    const itemIdx = group.items.indexOf(modal.name) + 1;
    path = `screenshots/features/${cat.idx}-${pad(groupIdx)}-${pad(itemIdx)}.png`;
  } else {
    path = `screenshots/features/${cat.idx}-${pad(groupIdx)}.png`;
  }
  const [loaded, setLoaded] = useStateF(false);
  const [errored, setErrored] = useStateF(false);

  return (
    <div className="fm-shot">
      <div className="fm-shot-grid" aria-hidden />
      {!errored && (
        <img
          src={path}
          alt=""
          className={'fm-shot-img' + (loaded ? ' loaded' : '')}
          onLoad={() => setLoaded(true)}
          onError={() => setErrored(true)}
        />
      )}
      {!loaded && (
        <div className="fm-shot-label">
          <span className="fm-shot-icon">▢</span>
          <span>截圖待補</span>
          <code className="fm-shot-path">{path.replace('screenshots/features/', '')}</code>
        </div>
      )}
      <div className="fm-shot-meta">SCREEN · 16:9</div>
    </div>
  );
}

window.LGFeatures = { Features };