import fs from "node:fs";
import ts from "typescript";

const sourcePath = new URL("../lib/i18n.ts", import.meta.url);
const outputPath = new URL("../lib/i18n-supplements.ts", import.meta.url);
const targetLanguage = {
  "zh-CN": "zh-CN",
  "ja-JP": "ja",
  "ko-KR": "ko",
  "vi-VN": "vi",
  "id-ID": "id",
  "de-DE": "de",
  "fr-FR": "fr",
  "ru-RU": "ru",
  "es-ES": "es",
  "pt-PT": "pt-PT",
};

const manualOverrides = {
  "zh-CN": { "reader.sendReadReceipt": "发送已读回执" },
  "ja-JP": { "reader.sendReadReceipt": "開封確認を送信" },
  "ko-KR": { "reader.sendReadReceipt": "읽음 확인 보내기" },
  "vi-VN": { "reader.sendReadReceipt": "Gửi xác nhận đã đọc" },
  "id-ID": {
    "reader.sendReadReceipt": "Kirim tanda terima telah dibaca",
    "sharing.mountedShare": "Berbagi terpasang",
  },
  "de-DE": {
    "reader.sendReadReceipt": "Lesebestätigung senden",
    "sharing.mountedShare": "Eingebundene Freigabe",
  },
  "fr-FR": {
    "reader.sendReadReceipt": "Envoyer l’accusé de lecture",
    "sharing.mountedShare": "Partage monté",
  },
  "ru-RU": {
    "reader.sendReadReceipt": "Отправить уведомление о прочтении",
    "sharing.mountedShare": "Подключённый общий ресурс",
  },
  "es-ES": {
    "mail.highPriority": "Alta prioridad",
    "reader.sendReadReceipt": "Enviar confirmación de lectura",
    "sharing.mountedShare": "Recurso compartido montado",
  },
  "pt-PT": {
    "mail.savedSearches": "Pesquisas guardadas",
    "reader.sendReadReceipt": "Enviar confirmação de leitura",
    "sharing.mountedShare": "Partilha montada",
    "info.appVersion": "Versão da aplicação: {version}",
  },
};

function loadRawDictionaries() {
  const source = fs.readFileSync(sourcePath, "utf8")
    .replace('import { i18nSupplements } from "./i18n-supplements";\n\n', "")
    .replace("      ...(i18nSupplements[option.value as keyof typeof i18nSupplements] ?? {}),\n", "")
    .replace("const rawDictionaries =", "export const rawDictionaries =");
  const javascript = ts.transpileModule(source, {
    compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
  }).outputText;
  const module = { exports: {} };
  new Function("module", "exports", javascript)(module, module.exports);
  return module.exports.rawDictionaries;
}

function protectPlaceholders(value) {
  const placeholders = [];
  return {
    text: value.replace(/\{[a-zA-Z0-9_]+\}/g, (placeholder) => {
      const token = `ZXQPH${placeholders.length}QXZ`;
      placeholders.push([token, placeholder]);
      return token;
    }),
    placeholders,
  };
}

function restorePlaceholders(value, placeholders) {
  let restored = value;
  for (const [token, placeholder] of placeholders) {
    restored = restored.replaceAll(token, placeholder);
  }
  return restored;
}

async function translateOne(locale, [key, value]) {
  const protectedValue = protectPlaceholders(value);
  const url = new URL("https://translate.googleapis.com/translate_a/single");
  url.searchParams.set("client", "gtx");
  url.searchParams.set("sl", "en");
  url.searchParams.set("tl", targetLanguage[locale]);
  url.searchParams.set("dt", "t");
  url.searchParams.set("q", protectedValue.text);

  let response;
  for (let attempt = 1; attempt <= 4; attempt += 1) {
    response = await fetch(url);
    if (response.ok) break;
    if (attempt === 4) throw new Error(`${locale}.${key}: translation failed with HTTP ${response.status}`);
    await new Promise((resolve) => setTimeout(resolve, attempt * 1000));
  }
  const payload = await response.json();
  const translated = (payload[0] ?? []).map((part) => part[0] ?? "").join("").trim();
  const restored = restorePlaceholders(translated, protectedValue.placeholders);
  const expected = [...value.matchAll(/\{[a-zA-Z0-9_]+\}/g)].map((match) => match[0]).sort();
  const actual = [...restored.matchAll(/\{[a-zA-Z0-9_]+\}/g)].map((match) => match[0]).sort();
  if (JSON.stringify(expected) !== JSON.stringify(actual)) {
    throw new Error(`${locale}.${key}: placeholder mismatch`);
  }
  return [key, restored];
}

const dictionaries = loadRawDictionaries();
const english = dictionaries["en-US"];
let supplements = {};
if (fs.existsSync(outputPath)) {
  const existing = fs.readFileSync(outputPath, "utf8");
  supplements = JSON.parse(existing.slice(existing.indexOf("{"), existing.lastIndexOf("} as const;") + 1));
}
const requestedLocales = process.argv.slice(2);
const locales = requestedLocales.length ? requestedLocales : Object.keys(targetLanguage);
for (const locale of locales) {
  if (!targetLanguage[locale]) throw new Error(`Unsupported locale: ${locale}`);
  const missing = Object.entries(english).filter(([key]) => !(key in dictionaries[locale]) && !(key in (supplements[locale] ?? {})));
  supplements[locale] = supplements[locale] ?? {};
  for (let offset = 0; offset < missing.length; offset += 12) {
    const translated = await Promise.all(missing.slice(offset, offset + 12).map((entry) => translateOne(locale, entry)));
    Object.assign(supplements[locale], Object.fromEntries(translated));
    process.stdout.write(`\r${locale}: ${Math.min(offset + 12, missing.length)}/${missing.length}`);
  }
  process.stdout.write("\n");
}
for (const [locale, overrides] of Object.entries(manualOverrides)) {
  supplements[locale] = { ...(supplements[locale] ?? {}), ...overrides };
}

const output = `// Generated by scripts/fill-i18n-supplements.mjs.\n` +
  `// Contains webmail UI translations only; /admin remains English-only.\n` +
  `export const i18nSupplements = ${JSON.stringify(supplements, null, 2)} as const;\n`;
fs.writeFileSync(outputPath, output);
