const fs = require('fs');
const path = require('path');

const ROOT = path.resolve(__dirname, '..');
const LOCALES_DIR = path.join(ROOT, 'src', 'i18n', 'locales');
const BASE_LOCALE = 'de.json';
const CORE_NAMESPACES = [
  'common',
  'navigation',
  'club',
  'members',
  'diary',
  'trainingStats',
  'courtDrawingTool'
];

const GERMAN_MARKERS = [
  'Mitglied',
  'Mitglieder',
  'Training',
  'Verein',
  'Bearbeiten',
  'Loeschen',
  'Löschen',
  'Zugriff',
  'Aufschlag',
  'Ziel',
  'Schlag',
  'Gruppe',
  'Gruppen',
  'Heute',
  'Zur Startseite'
];

const PLACEHOLDER_PATTERN = /\{[^}]+\}/g;

const NATIVE_CHARACTER_HINTS = {
  fr: /[àâæçéèêëîïôœùûüÿ]/i,
  es: /[áéíóúñü¡¿]/i,
  it: /[àèéìíîòóù]/i,
  pl: /[ąćęłńóśźż]/i,
  de: /[äöüß]/i,
  'de-CH': /[äöü]/i,
  ja: /[\u3040-\u30ff\u4e00-\u9faf]/,
  zh: /[\u4e00-\u9faf]/,
  th: /[\u0e00-\u0e7f]/,
  tl: null,
  fil: null,
  'en-GB': null,
  'en-US': null,
  'en-AU': null
};

function flatten(obj, prefix = '') {
  const out = {};
  for (const [key, value] of Object.entries(obj || {})) {
    const nextKey = prefix ? `${prefix}.${key}` : key;
    if (value && typeof value === 'object' && !Array.isArray(value)) {
      Object.assign(out, flatten(value, nextKey));
    } else {
      out[nextKey] = value;
    }
  }
  return out;
}

function pickNamespaces(source) {
  return Object.fromEntries(CORE_NAMESPACES.map(namespace => [namespace, source[namespace] || {}]));
}

function loadJson(filePath) {
  return JSON.parse(fs.readFileSync(filePath, 'utf8'));
}

function deepMerge(base, override) {
  if (!base || typeof base !== 'object' || Array.isArray(base)) {
    return override ?? base;
  }
  const result = { ...base };
  for (const [key, value] of Object.entries(override || {})) {
    if (
      value &&
      typeof value === 'object' &&
      !Array.isArray(value) &&
      result[key] &&
      typeof result[key] === 'object' &&
      !Array.isArray(result[key])
    ) {
      result[key] = deepMerge(result[key], value);
    } else {
      result[key] = value;
    }
  }
  return result;
}

function getLocaleCode(localeFile) {
  return localeFile.replace(/\.json$/, '');
}

function extractPlaceholders(value) {
  if (typeof value !== 'string') {
    return [];
  }
  return Array.from(value.matchAll(PLACEHOLDER_PATTERN)).map(match => match[0]).sort();
}

function auditLocale(localeFile, baseFlat) {
  const de = loadJson(path.join(LOCALES_DIR, BASE_LOCALE));
  const data = loadJson(path.join(LOCALES_DIR, localeFile));
  const merged = deepMerge(JSON.parse(JSON.stringify(de)), data);
  const flat = flatten(pickNamespaces(merged));
  const localeCode = getLocaleCode(localeFile);
  const missing = Object.keys(baseFlat).filter(key => !(key in flat));
  const sameAsDe = Object.keys(baseFlat).filter(key => flat[key] === baseFlat[key]);
  const germanHits = Object.entries(flat)
    .filter(([, value]) => typeof value === 'string' && GERMAN_MARKERS.some(marker => value.includes(marker)))
    .map(([key, value]) => `${key} = ${value}`);

  const placeholderMismatches = Object.entries(baseFlat)
    .filter(([key, value]) => {
      if (!(key in flat) || typeof value !== 'string' || typeof flat[key] !== 'string') {
        return false;
      }
      const basePlaceholders = extractPlaceholders(value);
      const localePlaceholders = extractPlaceholders(flat[key]);
      return JSON.stringify(basePlaceholders) !== JSON.stringify(localePlaceholders);
    })
    .map(([key, value]) => `${key} = base:${value} | locale:${flat[key]}`);

  const nativeCharHint = NATIVE_CHARACTER_HINTS[localeCode];
  const nativeCharCoverage = nativeCharHint
    ? Object.entries(flat)
      .filter(([, value]) => typeof value === 'string' && value.trim())
      .filter(([, value]) => nativeCharHint.test(value))
      .length
    : null;

  return {
    localeFile,
    localeCode,
    missing,
    sameAsDe,
    germanHits,
    placeholderMismatches,
    nativeCharCoverage
  };
}

function printSection(title, entries, limit = 20) {
  console.log(title);
  if (!entries.length) {
    console.log('  none');
    return;
  }
  for (const entry of entries.slice(0, limit)) {
    console.log(`  ${entry}`);
  }
  if (entries.length > limit) {
    console.log(`  ... ${entries.length - limit} more`);
  }
}

function main() {
  const localeArgs = process.argv.slice(2);
  const availableLocales = fs.readdirSync(LOCALES_DIR)
    .filter(file => file.endsWith('.json') && file !== BASE_LOCALE)
    .sort();

  const locales = localeArgs.length
    ? localeArgs.map(arg => (arg.endsWith('.json') ? arg : `${arg}.json`))
    : availableLocales;

  const base = loadJson(path.join(LOCALES_DIR, BASE_LOCALE));
  const baseFlat = flatten(pickNamespaces(base));

  let hasFailures = false;

  for (const localeFile of locales) {
    if (!availableLocales.includes(localeFile)) {
      console.error(`Unknown locale: ${localeFile}`);
      hasFailures = true;
      continue;
    }

    const result = auditLocale(localeFile, baseFlat);
    console.log(`\n## ${localeFile}`);
    console.log(`missing keys: ${result.missing.length}`);
    console.log(`same as de: ${result.sameAsDe.length}`);
    console.log(`german marker hits: ${result.germanHits.length}`);
    console.log(`placeholder mismatches: ${result.placeholderMismatches.length}`);
    if (result.nativeCharCoverage !== null) {
      console.log(`entries with native characters: ${result.nativeCharCoverage}`);
    }

    if (result.missing.length || result.germanHits.length || result.placeholderMismatches.length) {
      hasFailures = true;
    }

    printSection('Missing keys', result.missing);
    printSection('Same as de', result.sameAsDe);
    printSection('German marker hits', result.germanHits);
    printSection('Placeholder mismatches', result.placeholderMismatches);
  }

  if (hasFailures) {
    process.exitCode = 1;
  }
}

main();
