// 日曆事件繁體中文化：規則對照優先，剩餘英文再用 MyMemory 免費 API（結果快取）
import { getCachedJSON, putCachedJSON } from './db.js';

const SOURCE_ZH = {
  'Federal Reserve': '美國聯準會',
  BLS: '美國勞動統計局',
  BEA: '美國經濟分析局',
  'Nasdaq earnings': 'Nasdaq 財報',
  'Market calendar': '市場日曆',
  'FRED releases': 'FRED 發布日程',
  'Global markets': '全球市場',
  ECB: '歐洲央行',
  BOJ: '日本央行',
  BOE: '英格蘭銀行',
};

const TITLE_RULES = [
  [/Consumer Price Index for All Urban Consumers/i, 'CPI 消費者物價（通膨）'],
  [/Consumer Price Index|CPI/i, 'CPI 通膨'],
  [/Employment Situation|Nonfarm Payrolls|Nonfarm/i, '非農就業 / 失業率'],
  [/Producer Price Index|PPI/i, 'PPI 生產者物價'],
  [/Job Openings and Labor Turnover|Job Openings|JOLTS/i, 'JOLTS 職缺'],
  [/Import and Export Price/i, '進出口物價'],
  [/Real Earnings/i, '實質薪資'],
  [/Gross Domestic Product|GDP/i, 'GDP 國內生產毛額'],
  [/Personal Income and Outlays|Personal Income|Personal Outlays|PCE/i, 'PCE / 個人收入支出'],
  [/International Trade in Goods and Services/i, '國際貿易'],
  [/Corporate Profits/i, '企業利潤'],
  [/FOMC Meeting Minutes|FOMC minutes/i, 'FOMC 會議紀要'],
  [/FOMC.*SEP|SEP.*FOMC|dot plot/i, 'FOMC 利率決議 + 點陣圖'],
  [/FOMC|Federal Open Market Committee/i, 'FOMC 利率決議'],
  [/Retail Sales/i, '零售銷售'],
  [/Industrial Production/i, '工業生產'],
  [/Housing Starts|Building Permits/i, '住宅相關數據'],
  [/Jackson Hole/i, 'Jackson Hole 全球央行年會'],
  [/ECB 利率決議/i, 'ECB 利率決議'],
  [/日本央行 利率決議/i, '日本央行 利率決議'],
  [/英央行 MPC/i, '英央行 MPC 利率決議'],
  [/初領失業|Jobless Claims/i, '初領失業救濟金'],
  [/ADP/i, 'ADP 私部門就業'],
  [/密西根|Surveys of Consumers/i, '密西根消費者信心'],
  [/成屋銷售|Existing Home/i, '成屋銷售'],
  [/新屋開工|New Residential Construction/i, '新屋開工 / 營建許可'],
  [/耐久財|Manufacturer's Shipments/i, '耐久財 / 工廠接單出貨'],
  [/工業生產|Industrial Production/i, '工業生產 / 產能利用率'],
  [/零售銷售|Retail and Food Services/i, '零售銷售'],
  [/月選擇權結算/i, '月選擇權結算'],
  [/四巫日/i, '四巫日（衍生品結算）'],
  [/美股休市/i, '美股休市'],
  [/Employment Cost Index|ECI/i, '就業成本指數 ECI'],
  [/Productivity and Costs/i, '生產力 / 單位成本'],
];

const PHRASE_RULES = [
  [/Summary of Economic Projections/i, '經濟預測摘要'],
  [/dot plot/i, '點陣圖'],
  [/policy statement and interest rate decision/i, '政策聲明與利率決議'],
  [/News Release/i, '新聞發布'],
  [/U\.S\./gi, '美國'],
  [/EPS forecast/i, 'EPS 預估'],
  [/fiscal quarter ending/i, '財季截止'],
  [/FOMC minutes/i, 'FOMC 會議紀要'],
  [/Federal Reserve/i, '美國聯準會'],
  [/Interest Rate Decision/i, '利率決議'],
  [/All Urban Consumers/i, '所有城市消費者'],
  [/seasonally adjusted/i, '季調'],
];

function hasLatin(text) {
  return /[A-Za-z]{3,}/.test(String(text || ''));
}

function applyRules(text, rules) {
  let out = String(text || '').trim();
  if (!out) return '';
  for (const [re, rep] of rules) out = out.replace(re, rep);
  out = out
    .replace(/\bET\b/g, '美東')
    .replace(/\bEST\b/g, '美東')
    .replace(/\bAM\b/g, '上午')
    .replace(/\bPM\b/g, '下午')
    .replace(/\s+/g, ' ')
    .trim();
  return out;
}

function localizeTitle(title) {
  const t = String(title || '');
  for (const [re, rep] of TITLE_RULES) {
    if (re.test(t)) return rep;
  }
  return applyRules(t.replace(/^U\.S\.\s*/i, '').replace(/\s+News Release.*$/i, ''), TITLE_RULES);
}

function localizeNote(note) {
  return applyRules(note, PHRASE_RULES);
}

function localizeTime(time) {
  if (!time) return '';
  return String(time)
    .replace(/\bET\b/g, '美東')
    .replace(/\bAM\b/g, '上午')
    .replace(/\bPM\b/g, '下午')
    .trim();
}

function localizeEarningsNote(note, symbol, name) {
  const parts = [];
  if (name && name !== symbol) parts.push(name);
  const eps = String(note || '').match(/EPS forecast\s+([\d.\-]+)/i);
  if (eps) parts.push(`EPS 預估 ${eps[1]}`);
  const fq = String(note || '').match(/·\s*([\d/]+)\s*$/);
  if (fq) parts.push(`財季 ${fq[1]}`);
  return parts.join(' · ') || `${symbol} 財報`;
}

async function translateWithMyMemory(text) {
  const src = String(text || '').trim().slice(0, 450);
  if (!src || !hasLatin(src)) return src;
  const cacheKey = `tr:en-zh-TW:${src}`;
  const cached = getCachedJSON(cacheKey, 30 * 86400000);
  if (cached) return cached;
  try {
    const url = `https://api.mymemory.translated.net/get?q=${encodeURIComponent(src)}&langpair=en|zh-TW`;
    const res = await fetch(url, { headers: { 'User-Agent': 'finance-dashboard/1.0' } });
    if (!res.ok) return src;
    const data = await res.json();
    let out = data?.responseData?.translatedText || src;
    if (out === src || /QUERY LENGTH LIMIT/i.test(out)) return src;
    out = out.replace(/&quot;/g, '"').replace(/&#39;/g, "'").trim();
    putCachedJSON(cacheKey, out);
    return out;
  } catch {
    return src;
  }
}

async function ensureZh(text, apiBudget) {
  let out = applyRules(text, PHRASE_RULES);
  if (!hasLatin(out)) return out;
  if (apiBudget.remaining <= 0) return out;
  apiBudget.remaining--;
  return translateWithMyMemory(out);
}

export async function localizeCalendarPayload(payload) {
  const apiBudget = { remaining: 24 };
  const events = [];
  for (const ev of payload.events || []) {
    let title = ev.title || '';
    let note = ev.note || '';
    if (ev.category === 'earnings') {
      title = title.includes('財報') ? title : `${ev.symbol || ''} 財報`.trim();
      note = localizeEarningsNote(note, ev.symbol, (note.split('·')[0] || '').trim());
    } else {
      title = localizeTitle(title);
      note = localizeNote(note);
      if (hasLatin(title)) title = await ensureZh(title, apiBudget);
      if (hasLatin(note)) note = await ensureZh(note, apiBudget);
    }
    events.push({
      ...ev,
      title,
      note,
      time: localizeTime(ev.time),
      source: SOURCE_ZH[ev.source] || ev.source,
    });
  }
  return {
    ...payload,
    events,
    sources: (payload.sources || []).map(s => ({
      ...s,
      name: SOURCE_ZH[s.name] || s.name,
      ok: s.ok,
      error: s.error,
    })),
  };
}
