// cSpell:ignore Tolgee
import fs from 'node:fs/promises';
import path from 'node:path';
import { format } from 'prettier';
import { getAllProjectLanguages, getRemoteTranslations } from './api.js';
import type { TranslationRes } from './utils.js';

const RES_DIR = path.resolve(process.cwd(), 'src', 'resources');

const countKeys = (obj: TranslationRes) => {
  let count = 0;
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  Object.entries(obj).forEach(([_, value]) => {
    if (typeof value === 'string') {
      count++;
    } else {
      count += countKeys(value);
    }
  });
  return count;
};

const getBaseTranslations = async (baseLanguage: { tag: string }) => {
  try {
    const baseTranslationsStr = await fs.readFile(
      path.resolve(RES_DIR, `${baseLanguage.tag}.json`),
      { encoding: 'utf8' }
    );
    const baseTranslations = JSON.parse(baseTranslationsStr);
    return baseTranslations;
  } catch (e) {
    console.error('base language:', JSON.stringify(baseLanguage));
    console.error('Failed to read base language', e);
    const translations = await getRemoteTranslations(baseLanguage.tag);
    await fs.writeFile(
      path.resolve(RES_DIR, `${baseLanguage.tag}.json`),
      JSON.stringify(translations, null, 4)
    );
  }
};

const main = async () => {
  console.log('Loading project languages...');
  const languages = await getAllProjectLanguages();
  const baseLanguage = languages.find(language => language.base);
  if (!baseLanguage) {
    console.error(JSON.stringify(languages));
    throw new Error('Could not find base language');
  }
  console.log(`Loading ${baseLanguage.tag} languages translations as base...`);

  const baseTranslations = await getBaseTranslations(baseLanguage);
  const baseKeyNum = countKeys(baseTranslations);
  const languagesWithTranslations = await Promise.all(
    languages.map(async language => {
      console.log(`Loading ${language.tag} translations...`);
      const translations = await getRemoteTranslations(language.tag);
      const keyNum = countKeys(translations);

      return {
        ...language,
        translations,
        completeRate: keyNum / baseKeyNum,
      };
    })
  );

  const availableLanguages = languagesWithTranslations.filter(
    language => language.completeRate > 0.8
  );

  availableLanguages
    // skip base language
    .filter(i => !i.base)
    .forEach(async language => {
      await fs.writeFile(
        path.resolve(RES_DIR, `${language.tag}.json`),
        JSON.stringify(
          {
            '// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.':
              '',
            ...language.translations,
          },
          null,
          4
        ) + '\n'
      );
    });

  console.log('Generating meta data...');
  const code = `// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
        // Run \`pnpm run download-resources\` to regenerate.
        // To overwrite this, please overwrite download.ts script.
        ${availableLanguages
          .map(
            language =>
              `import ${language.tag.replaceAll('-', '_')} from './${
                language.tag
              }.json'`
          )
          .join('\n')}

        export const LOCALES = [
            ${availableLanguages
              // eslint-disable-next-line @typescript-eslint/no-unused-vars
              .map(({ translations, ...language }) =>
                JSON.stringify({
                  ...language,
                  res: '__RES_PLACEHOLDER',
                }).replace(
                  '"__RES_PLACEHOLDER"',
                  language.tag.replaceAll('-', '_')
                )
              )
              .join(',\n')}
        ] as const;
        `;

  await fs.writeFile(
    path.resolve(RES_DIR, 'index.ts'),
    format(code, {
      parser: 'typescript',
      singleQuote: true,
      trailingComma: 'es5',
      tabWidth: 4,
      arrowParens: 'avoid',
    })
  );
  console.log('Done');
};

main();
