/*
 This file is part of GNU Taler
 (C) 2020 Taler Systems S.A.

 GNU Taler is free software; you can redistribute it and/or modify it under the
 terms of the GNU General Public License as published by the Free Software
 Foundation; either version 3, or (at your option) any later version.

 GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

 You should have received a copy of the GNU General Public License along with
 GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */

/**
 * Convert a <lang>.po file into a JavaScript / TypeScript expression.
 */

// @ts-ignore
import * as po2jsonLib from "po2json";
import * as fs from "node:fs";
import glob = require("glob");

//types defined by the po2json library
type Header = {
  domain: string;
  lang: string;
  'plural_forms': string;
};

type MessagesType = Record<string, undefined | Array<string>> & { "": Header }
interface pojsonType {
  // X-Domain or 'messages'
  domain: string;
  locale_data: {
    messages: MessagesType
  }
}
// ----------- end pf po2json

interface StringsType {
  // X-Domain or 'messages'
  domain: string;
  lang: string;
  completeness: number,
  'plural_forms': string;
  locale_data: {
    messages: Record<string, undefined | Array<string>>
  }
}

// This prelude match the types above
const TYPES_FOR_STRING_PRELUDE = `
export interface StringsType {
  domain: string;
  lang: string;
  completeness: number;
  'plural_forms': string;
  locale_data: {
    messages: Record<string, unknown>;
  };
};
`;

const DEFAULT_STRING_PRELUDE = `${TYPES_FOR_STRING_PRELUDE}export const strings: Record<string,StringsType> = {};\n\n`


export function po2ts(): void {
  const files = glob.sync("src/i18n/*.po");

  if (files.length === 0) {
    console.error("no .po files found in src/i18n/");
    process.exit(1);
  }

  console.log(files);

  let prelude: string;
  try {
    prelude = fs.readFileSync("src/i18n/strings-prelude", "utf-8")
  } catch (e) {
    prelude = DEFAULT_STRING_PRELUDE
  }

  const chunks = [prelude];

  for (const filename of files) {
    const m = filename.match(/([a-zA-Z0-9-_]+).po/);

    if (!m) {
      console.error("error: unexpected filename (expected <lang>.po)");
      process.exit(1);
    }

    const lang = m[1];
    const poAsJson: pojsonType = po2jsonLib.parseFileSync(filename, {
      format: "jed1.x",
      fuzzy: true,
    });
    const header = poAsJson.locale_data.messages[""]
    if (!header.lang) {
      console.error("error: missing 'Language' property in " + filename);
      process.exit(1);
    }
    const total = calculateTotalTranslations(poAsJson.locale_data.messages)
    const completeness =
      (header.lang === "en"
        ? 100 // 'en' is always complete
        : Math.floor(total.translations * 100 / total.keys));

    const strings: StringsType = {
      locale_data: poAsJson.locale_data,
      domain: poAsJson.domain,
      plural_forms: header.plural_forms,
      lang: header.lang,
      completeness: Number.isNaN(completeness) ? 0 : completeness,
    }
    const value = JSON.stringify(strings, undefined, 2)
    const s = `strings['${lang}'] = ${value};\n\n`
    chunks.push(s);
  }

  const tsContents = chunks.join("");

  fs.writeFileSync("src/i18n/strings.ts", tsContents);
}

function calculateTotalTranslations(msgs: MessagesType): { keys: number, translations: number } {
  const kv = Object.entries(msgs)
  const [keys, translations] = kv.reduce(([total, withTranslation], translation) => {
    if (!translation || translation.length !== 2 || !translation[1]) {
      //current key is empty
      return [total, withTranslation]
    }
    const v = translation[1]
    if (!Array.isArray(v)) {
      // this is not a translation
      return [total, withTranslation]
    }
    if (!v.length || !v[0].length) {
      //translation is missing
      return [total + 1, withTranslation]
    }
    //current key has a translation
    return [total + 1, withTranslation + 1]
  }, [0, 0])
  return { keys, translations }
}