// 「システムの部分に触れていないか」をまとめて点検する。
//
// 翻訳は文字列を差し替える作業なので、うっかり **仕組みの側** を書き換えると
// 例外も出ないまま静かに壊れる。これまでに踏んだのは
//   ・CSS の値を訳す      → ゲージが真っ白になる
//   ・DOM の列挙値を訳す  → 窓が小窓になる
//   ・Web Audio の列挙値  → 音が出なくなる
//   ・保存キーを訳す      → セーブが読めなくなる
// の四種。ここでは英語の原版と日本語版を機械的に突き合わせ、
// 「訳文以外が変わっていないか」を確かめる。
import fs from 'fs';

const EN = fs.readFileSync(process.argv[2] || 'app/game/index.html', 'utf8');
const JA = fs.readFileSync(process.argv[3] || 'build/index.html', 'utf8');

const problems = [];
const ok = [];

const list = (src, re, g = 1) => [...src.matchAll(re)].map(m => m[g]);
// 日本語化で **意図して足している** もの。字体の切替を設定に追加するため、
// 要素 1 つとその初期化が増える。これは翻訳ではないので、増分として許す。
const MINE = new Set(['opt-jafont', 'DOMContentLoaded', 'loading', 'jafont']);

const cmp = (label, re, g = 1, opts = {}) => {
  const a = list(EN, re, g), b = list(JA, re, g);
  const sa = new Set(a), sb = new Set(b);
  const lost = [...sa].filter(x => !sb.has(x));
  const added = opts.allowAdded ? [] : [...sb].filter(x => !sa.has(x) && !MINE.has(x));
  if (lost.length || added.length) {
    problems.push(`${label}: 消えた ${lost.length} 件 ${JSON.stringify(lost.slice(0, 6))}`
      + (added.length ? ` / 増えた ${added.length} 件 ${JSON.stringify(added.slice(0, 6))}` : ''));
  } else ok.push(`${label} (${sa.size} 種)`);
};

// 保存に関わる鍵。訳すとセーブが読めなくなる。
cmp('localStorage の鍵', /localStorage\.(?:getItem|setItem|removeItem)\(\s*["']([^"']+)["']/g);
// DOM の id / クラス。訳すと結び付きが切れる。
cmp('getElementById', /getElementById\(\s*["']([^"']+)["']/g);
cmp('querySelector', /querySelector(?:All)?\(\s*["']([^"']+)["']/g);
cmp('classList の操作', /classList\.\w+\(\s*["']([^"']+)["']/g);
cmp('setAttribute の名前', /setAttribute\(\s*["']([^"']+)["']/g);
cmp('addEventListener の種別', /addEventListener\(\s*["']([^"']+)["']/g);
// Web Audio / canvas の列挙値
cmp('列挙値の代入', /\.(?:type|oversample|textBaseline|textAlign|lineCap|lineJoin|panningModel)\s*=\s*["']([^"']+)["']/g);
cmp('状態の比較', /\.(?:state|readyState|visibilityState|protocol)\s*[!=]==?\s*["']([^"']+)["']/g);
// ネットワークの宛先
cmp('fetch の宛先', /fetch\(\s*["']([^"']+)["']/g);
// CSS の宣言（style へ直接入れているもの）
cmp('style への代入', /\.style\.(\w+)\s*=/g);

// セーブのスキーマ番号
const ver = s => (s.match(/stamp:Date\.now\(\),\s*v:(\d+)/) || s.match(/v:(\d+),\s*stamp/) || [])[1];
if (ver(EN) !== ver(JA)) problems.push(`セーブのスキーマ番号が変わっています: ${ver(EN)} -> ${ver(JA)}`);
else ok.push(`セーブのスキーマ番号 (v${ver(EN)})`);

// script の数（丸ごと壊していないか）
const nEN = (EN.match(/<script>/g) || []).length, nJA = (JA.match(/<script>/g) || []).length;
if (nEN !== nJA) problems.push(`script の数が違います: ${nEN} -> ${nJA}`);
else ok.push(`script の数 (${nEN})`);

console.log('=== 触れていないことを確かめた項目 ===');
ok.forEach(o => console.log('  OK  ' + o));
if (problems.length) {
  console.log('\n=== 要確認 ===');
  problems.forEach(p => console.log('  !!  ' + p));
} else {
  console.log('\nシステム側の書き換えは見つかりませんでした。');
}
process.exit(problems.length ? 1 : 0);
