import fs from 'node:fs';
const html = fs.readFileSync(new URL('./index.html', import.meta.url).pathname,'utf8');

// 抽出 safeJson 與 friendlyErr 求值
const grab = (name) => {
  const i = html.indexOf(`function ${name}(`);
  if (i < 0) throw new Error(`找不到 ${name}`);
  let d=0, j=html.indexOf('{', i);
  for (let k=j;k<html.length;k++){ if(html[k]==='{')d++; if(html[k]==='}'){d--; if(!d){ return html.slice(i,k+1);} } }
  throw new Error('括號不平衡');
};
const fn = new Function(grab('safeJson') + '\n' + grab('friendlyErr') + '\nreturn {safeJson, friendlyErr};')();

let pass=0, fail=0;
const t=(l,c,e='')=>{c?(console.log('PASS:',l),pass++):(console.log('FAIL:',l,e),fail++)};

// ① safeJson：非 JSON 不可拋例外（同事撞到的 404 HTML 頁）
const html404 = '<!DOCTYPE html><html><body>404 Not Found</body></html>';
await fn.safeJson({ text: () => Promise.resolve(html404) })
  .then(d => t('404 HTML → 回空物件不拋錯', typeof d === 'object' && d !== null))
  .catch(e => t('404 HTML → 不該拋錯', false, e.message));

await fn.safeJson({ text: () => Promise.resolve('') })
  .then(d => t('空回應 → 回空物件', JSON.stringify(d)==='{}'))
  .catch(() => t('空回應 → 不該拋錯', false));

await fn.safeJson({ text: () => Promise.resolve('{"error":"帳號或密碼不對"}') })
  .then(d => t('正常 JSON 仍要解析得出來', d.error === '帳號或密碼不對'), )
  .catch(() => t('正常 JSON 不該拋錯', false));

// ② friendlyErr：不可把技術訊息噴給使用者
const leak = fn.friendlyErr(new Error('Unexpected non-whitespace character after JSON at position 4'));
t('JSON 錯誤 → 不外洩原文', !/JSON|position/i.test(leak), `實得: ${leak}`);
t('JSON 錯誤 → 說人話', /伺服器回應異常/.test(leak), `實得: ${leak}`);

const net = fn.friendlyErr(new Error('Failed to fetch'));
t('網路錯誤 → 既有訊息保留', /連線中斷/.test(net), `實得: ${net}`);

const ours = fn.friendlyErr(new Error('帳號或密碼不對——用你在知識庫網站設定的那組'));
t('我們自己的中文訊息 → 原樣顯示', /帳號或密碼不對/.test(ours), `實得: ${ours}`);

const stack = fn.friendlyErr(new Error('TypeError: Cannot read properties of undefined'));
t('英文技術訊息 → 收斂不外洩', !/TypeError|undefined/.test(stack), `實得: ${stack}`);

console.log(`\n=== ${pass} passed, ${fail} failed ===`);
process.exit(fail?1:0);
