import fs from 'fs';
import path from 'path';

const LANGS = ['de', 'fr', 'it', 'es', 'pt', 'hi', 'bn', 'id', 'zh', 'ja'];
const LOCAL_PATH = path.resolve('src/lang/local.ts');
const CACHE_PATH = path.resolve('scripts/translation-cache.json');

function escapeString(str) {
  return str
    .replace(/\\/g, '\\\\')
    .replace(/"/g, '\\"')
    .replace(/\n/g, '\\n')
    .replace(/\r/g, '\\r')
    .replace(/\t/g, '\\t');
}

function unescapeString(str) {
  return str.replace(/\\"/g, '"').replace(/\\n/g, '\n').replace(/\\\\/g, '\\');
}

function parseEntries(content) {
  const regex = /(['"])([^'"]+)\1:\s*\{\s*ru:\s*"((?:\\.|[^"\\])*)"\s*,\s*en:\s*"((?:\\.|[^"\\])*)"\s*(?:,\s*)?\}/g;
  const entries = [];
  let m;
  while ((m = regex.exec(content)) !== null) {
    entries.push({
      key: m[2],
      quote: m[1],
      ru: unescapeString(m[3]),
      en: unescapeString(m[4]),
      start: m.index,
      end: m.index + m[0].length,
    });
  }
  return entries;
}

async function sleep(ms) {
  return new Promise((r) => setTimeout(r, ms));
}

async function translateMyMemory(text, lang) {
  const url = `https://api.mymemory.translated.net/get?q=${encodeURIComponent(text)}&langpair=en|${lang}`;
  const res = await fetch(url);
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  const data = await res.json();
  if (data.responseStatus !== 200) {
    throw new Error(data.responseDetails || 'Translation failed');
  }
  return data.responseData.translatedText;
}

async function translateText(text, lang) {
  if (!text.trim()) return text;
  for (let attempt = 0; attempt < 8; attempt++) {
    try {
      const result = await translateMyMemory(text, lang);
      await sleep(600 + attempt * 300);
      return result;
    } catch (err) {
      const wait = 3000 * (attempt + 1);
      console.warn(`  retry ${attempt + 1}/8 for ${lang}: ${err.message}`);
      await sleep(wait);
    }
  }
  return null;
}

function formatEntry(key, quote, ru, en, extra) {
  const lines = [
    `    ${quote}${key}${quote}: {`,
    `        ru: "${escapeString(ru)}",`,
    `        en: "${escapeString(en)}",`,
  ];
  for (const lang of LANGS) {
    lines.push(`        ${lang}: "${escapeString(extra[lang])}",`);
  }
  lines.push('    },');
  return lines.join('\n');
}

function applyToFile(content, entries, cache) {
  content = content.replace(
    "export type LangType = 'ru' | 'en';",
    "export type LangType = 'ru' | 'en' | 'de' | 'fr' | 'it' | 'es' | 'pt' | 'hi' | 'bn' | 'id' | 'zh' | 'ja';"
  );
  content = content.replace(
    /export type LocalItemType = \{\s*ru: string;\s*en: string;\s*\}/,
    `export type LocalItemType = {\n    ru: string;\n    en: string;\n    de: string;\n    fr: string;\n    it: string;\n    es: string;\n    pt: string;\n    hi: string;\n    bn: string;\n    id: string;\n    zh: string;\n    ja: string;\n}`
  );

  for (let i = entries.length - 1; i >= 0; i--) {
    const entry = entries[i];
    const extra = {};
    for (const lang of LANGS) {
      extra[lang] = cache[`${lang}::${entry.en}`] ?? entry.en;
    }
    const replacement = formatEntry(entry.key, entry.quote, entry.ru, entry.en, extra);
    content = content.slice(0, entry.start) + replacement + content.slice(entry.end);
  }
  return content;
}

async function main() {
  let content = fs.readFileSync(LOCAL_PATH, 'utf8');
  const entries = parseEntries(content);
  console.log(`Found ${entries.length} entries`);

  const cache = fs.existsSync(CACHE_PATH)
    ? JSON.parse(fs.readFileSync(CACHE_PATH, 'utf8'))
    : {};

  const uniqueEn = [...new Set(entries.map((e) => e.en))];
  const totalNeeded = uniqueEn.length * LANGS.length;
  let done = Object.keys(cache).length;
  console.log(`Cache: ${done}/${totalNeeded}`);

  let translated = 0;
  const missing = [];

  for (const en of uniqueEn) {
    for (const lang of LANGS) {
      const cacheKey = `${lang}::${en}`;
      if (cache[cacheKey]) continue;
      translated++;
      process.stdout.write(`\r[${done + translated}/${totalNeeded}] ${lang}: ${en.slice(0, 55)}...`);
      const result = await translateText(en, lang);
      if (result) {
        cache[cacheKey] = result;
      } else {
        cache[cacheKey] = en;
        missing.push(cacheKey);
        console.warn(`\n  fallback to EN: ${cacheKey}`);
      }
      if (translated % 5 === 0) {
        fs.writeFileSync(CACHE_PATH, JSON.stringify(cache, null, 2));
      }
    }
  }

  console.log('\nApplying translations to file...');
  fs.writeFileSync(CACHE_PATH, JSON.stringify(cache, null, 2));
  content = applyToFile(content, entries, cache);
  fs.writeFileSync(LOCAL_PATH, content);
  console.log(`Done! Missing/fallback: ${missing.length}`);
}

main().catch((err) => {
  console.error(err);
  process.exit(1);
});
