import { promises, readFileSync } from 'fs';
import path from 'path';

interface AllTranslations {
  [path: string]: Translations;
}

interface Translations {
  [translationKey: string]: {
    message: string;
    missing: boolean;
  };
}

export class TranslationsService {
  private translationFiles: string[] = [];
  private defaultTranslations: Translations = {};

  constructor() {
    this.getTranslationFiles();
    this.getDefaultTranslations();
  }

  private async getTranslationFiles() {
    this.translationFiles = await promises.readdir(
      path.resolve(process.cwd(), 'translations')
    );
  }

  private async getDefaultTranslations() {
    this.defaultTranslations = JSON.parse(
      readFileSync(
        path.join(path.resolve(process.cwd(), 'translations'), 'default.json'),
        'utf-8'
      )
    );
  }

  private sortTranslations(translations: Translations) {
    const sortedKeys = Object.keys(translations).sort();

    return sortedKeys.reduce((prev, curr) => {
      prev[curr] = translations[curr];
      return prev;
    }, {} as Translations);
  }

  private markDiffs(t: Translations) {
    const defaultKeys = Object.keys(this.defaultTranslations);
    const translations = { ...t };

    for (const key of defaultKeys) {
      if (!(key in translations)) {
        translations[key] = {
          missing: true,
          message: this.defaultTranslations[key].message
        };
      } else {
        translations[key] = {
          ...translations[key],
          missing: !translations[key].message

          // NOTE: Removed translations[key].message === this.defaultTranslations[key].message
          // as certain translations into different languages can be the same as it is English.
          // Especially when they are single words.
        };
      }
    }

    for (const key of Object.keys(translations)) {
      if (!(key in this.defaultTranslations)) {
        // key should not be here
        delete translations[key];
      }
    }

    return translations;
  }

  public async readTranslations() {
    return this.translationFiles
      .filter(filename => filename.endsWith('json'))
      .reduce((prev, curr) => {
        const fileData = readFileSync(
          path.join(path.resolve(process.cwd(), 'translations'), curr),
          'utf-8'
        );

        prev[curr] = this.markDiffs(
          this.sortTranslations(JSON.parse(fileData))
        );

        return prev;
      }, {} as AllTranslations);
  }

  public async byName(name: string) {
    return this.markDiffs(
      JSON.parse(
        readFileSync(
          path.join(path.resolve(process.cwd(), 'translations'), name),
          'utf-8'
        )
      )
    );
  }
}
