// ═══════════════════════════════════════════════════════════
//  build-knowledge.mjs
//  把 content/raw/emmy（或舊版 ../emmy/emmy）的 Obsidian 知識庫快照成兩個 JSON：
//   - data/knowledge.json : 課綱/心法/案例/分類 全文 + 名詞/公司/單集的輕量索引 + linkMap
//   - data/notes.json     : 所有筆記全文（key = `${kind}:${id}`），給 /api/note 即時查單篇
//  emmy/ 在 app/ 之外，因此用建置腳本快照，不在執行期讀檔。
//  用法：cd app && npm run build:knowledge
// ═══════════════════════════════════════════════════════════
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const EMMY_CANDIDATES = [
  path.resolve(__dirname, '..', '..', 'content', 'raw', 'emmy'),
  path.resolve(__dirname, '..', '..', 'emmy', 'emmy'),
];
const EMMY = EMMY_CANDIDATES.find((p) => fs.existsSync(p));
const OUT_DIR = path.resolve(__dirname, '..', 'data');

if (!EMMY) {
  console.error(`找不到知識庫資料夾，已嘗試：\n${EMMY_CANDIDATES.join('\n')}`);
  process.exit(1);
}

// ── 小工具 ──
function parseFrontmatter(raw) {
  if (!raw.startsWith('---')) return { fm: {}, body: raw };
  const end = raw.indexOf('\n---', 3);
  if (end < 0) return { fm: {}, body: raw };
  const fmText = raw.slice(3, end).trim();
  const body = raw.slice(end + 4).replace(/^\s*\n/, '');
  const fm = {};
  for (const line of fmText.split('\n')) {
    const m = line.match(/^([\w\u4e00-\u9fff]+):\s*(.*)$/);
    if (!m) continue;
    let [, k, v] = m; v = v.trim();
    if (v.startsWith('[') && v.endsWith(']')) v = v.slice(1, -1).split(',').map(s => s.trim()).filter(Boolean);
    else v = v.replace(/^["']|["']$/g, '');
    fm[k] = v;
  }
  return { fm, body };
}
const firstHeading = (body) => { const m = body.match(/^#\s+(.+)$/m); return m ? m[1].trim() : null; };
function summarize(body) {
  for (let l of body.split('\n')) {
    l = l.trim();
    if (!l || /^#/.test(l) || /^[-|]/.test(l) || /^type:/.test(l)) continue;
    if (l.startsWith('>')) l = l.replace(/^>\s?/, '');
    l = l.replace(/\[\[([^\]|]+)(\|[^\]]+)?\]\]/g, '$1').replace(/\[([^\]]+)\]\([^)]+\)/g, '$1').replace(/[*`#]/g, '').trim();
    if (l.length > 4) return l.slice(0, 90);
  }
  return '';
}
function readDir(sub) {
  const dir = path.join(EMMY, sub);
  if (!fs.existsSync(dir)) return [];
  return fs.readdirSync(dir)
    .filter(f => f.endsWith('.md') && !f.endsWith('.bak') && !f.startsWith('.') && !f.startsWith('_'))
    .map(f => {
      const full = path.join(dir, f);
      if (!fs.statSync(full).isFile()) return null;
      const raw = fs.readFileSync(full, 'utf8');
      if (!raw.trim()) return null;
      const id = f.replace(/\.md$/, '');
      const { fm, body } = parseFrontmatter(raw);
      return { id, title: firstHeading(body) || id, fm, body };
    })
    .filter(Boolean);
}

// ── 累積器 ──
const linkMap = {};
const notes = {};
const setLink = (key, val, overwrite = true) => { if (key && (overwrite || !linkMap[key])) linkMap[key] = val; };
const addNote = (kind, n) => {
  notes[`${kind}:${n.id}`] = { kind, id: n.id, title: n.title, frontmatter: n.fm || {}, body: n.body };
};

// ── 1. 學習分類（含 總覽 / 心法地圖 / 練習題庫）──
const SPECIAL = { '總覽': 'overview', '心法地圖': 'principleMap', '練習題庫': 'quiz' };
let overview = null, principleMap = null, quiz = null;
const categories = [];
for (const n of readDir('學習分類')) {
  const node = { id: n.id, title: n.title, body: n.body, summary: summarize(n.body), frontmatter: n.fm };
  const special = SPECIAL[n.id];
  if (special === 'overview') { overview = node; setLink('學習分類/總覽', { kind: 'overview', id: n.id, title: n.title }); }
  else if (special === 'principleMap') { principleMap = node; setLink('學習分類/心法地圖', { kind: 'principleMap', id: n.id, title: n.title }); }
  else if (special === 'quiz') { quiz = node; setLink('學習分類/練習題庫', { kind: 'quiz', id: n.id, title: n.title }); }
  else categories.push(node);
  const kind = special || 'category';
  setLink(`學習分類/${n.id}`, { kind, id: n.id, title: n.title });
  setLink(n.id, { kind, id: n.id, title: n.title }, false);
  addNote(kind, n);
}

// ── 2. 案例講解 ──
const cases = [];
for (const n of readDir('案例講解')) {
  cases.push({ id: n.id, title: n.title, body: n.body, summary: summarize(n.body), frontmatter: n.fm });
  setLink(`案例講解/${n.id}`, { kind: 'case', id: n.id, title: n.title });
  setLink(n.id, { kind: 'case', id: n.id, title: n.title }, false);
  addNote('case', n);
}

// ── 3. 投資心法（單檔切成多條原則）──
const principles = [];
{
  const file = path.join(EMMY, 'Emmy 投資心法.md');
  if (fs.existsSync(file)) {
    const lines = fs.readFileSync(file, 'utf8').split('\n');
    let cur = null;
    const push = () => { if (cur) { cur.body = cur._lines.join('\n').trim(); delete cur._lines; principles.push(cur); } };
    for (const line of lines) {
      const m = line.match(/^##\s+(原則.+?)\s*$/);
      if (m) { push(); cur = { id: m[1].trim(), title: m[1].trim(), _lines: ['# ' + m[1].trim()] }; }
      else if (cur) cur._lines.push(line);
    }
    push();
    principles.forEach((p, i) => {
      p.num = i + 1;
      setLink(`Emmy 投資心法#${p.id}`, { kind: 'principle', id: p.id, title: p.title });
      setLink(p.id, { kind: 'principle', id: p.id, title: p.title }, false);
      addNote('principle', { id: p.id, title: p.title, body: p.body, fm: {} });
    });
  }
}

// ── 4. 名詞 / 公司 / 單集（輕量索引 + 全文存 notes）──
const index = [];
for (const n of readDir('名詞')) {
  const aliases = Array.isArray(n.fm.aliases) ? n.fm.aliases : [];
  index.push({ kind: 'term', id: n.id, title: n.title, aliases, sub: n.fm.category || '' });
  setLink(`名詞/${n.id}`, { kind: 'term', id: n.id, title: n.title });
  setLink(n.id, { kind: 'term', id: n.id, title: n.title }, false);
  aliases.forEach(a => setLink(a, { kind: 'term', id: n.id, title: n.title }, false));
  addNote('term', n);
}
for (const n of readDir('公司')) {
  const ticker = Array.isArray(n.fm.ticker) ? n.fm.ticker.join(' / ') : (n.fm.ticker || '');
  index.push({ kind: 'company', id: n.id, title: n.title, aliases: ticker ? [ticker] : [], sub: [n.fm.sector, ticker].filter(Boolean).join(' · ') });
  setLink(`公司/${n.id}`, { kind: 'company', id: n.id, title: n.title });
  setLink(n.id, { kind: 'company', id: n.id, title: n.title }, false);
  addNote('company', n);
}
for (const n of readDir('單集')) {
  index.push({ kind: 'episode', id: n.id, title: n.title, aliases: n.fm.episode ? [n.fm.episode] : [], sub: n.fm.date || '' });
  setLink(`單集/${n.id}`, { kind: 'episode', id: n.id, title: n.title });
  setLink(n.id, { kind: 'episode', id: n.id, title: n.title }, false);
  if (n.fm.episode) setLink(n.fm.episode, { kind: 'episode', id: n.id, title: n.title }, false);
  addNote('episode', n);
}

const counts = {
  terms: index.filter(x => x.kind === 'term').length,
  companies: index.filter(x => x.kind === 'company').length,
  episodes: index.filter(x => x.kind === 'episode').length,
};

const knowledge = {
  generatedAt: new Date().toISOString(),
  overview, principleMap, quiz,
  categories, cases, principles,
  index, counts, linkMap,
};

fs.mkdirSync(OUT_DIR, { recursive: true });
fs.writeFileSync(path.join(OUT_DIR, 'knowledge.json'), JSON.stringify(knowledge));
fs.writeFileSync(path.join(OUT_DIR, 'notes.json'), JSON.stringify(notes));

console.log('知識庫建置完成：');
console.log(`  學習分類 ${categories.length}　案例 ${cases.length}　心法 ${principles.length}`);
console.log(`  名詞 ${counts.terms}　公司 ${counts.companies}　單集 ${counts.episodes}`);
console.log(`  linkMap ${Object.keys(linkMap).length} 個鍵　notes ${Object.keys(notes).length} 篇`);
console.log(`  輸出 → ${path.relative(process.cwd(), path.join(OUT_DIR, 'knowledge.json'))}, notes.json`);
