# Copyright: Ankitects Pty Ltd and contributors
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html

import json
import sys
from typing import List, Literal, TypedDict

import stringcase

strings_json, translate_out, modules_out = sys.argv[1:]
modules = json.load(open(strings_json, encoding="utf8"))


class Variable(TypedDict):
    name: str
    kind: Literal["Any", "Int", "String", "Float"]


def methods() -> str:
    out = [ """import type { FluentVariable } from "@fluent/bundle";
import { getMessage } from "./i18n";

function translate(key: string, args: Record<string, FluentVariable> = {}): string {
    return getMessage(key, args) ?? `missing key: ${key}`;
}""" ]
    for module in modules:
        for translation in module["translations"]:
            key = stringcase.camelcase(translation["key"].replace("-", "_"))
            arg_types = get_arg_name_and_types(translation["variables"])
            args = get_args(translation["variables"])
            doc = translation["text"]
            out.append(
                f"""
/** {doc} */
export function {key}({arg_types}): string {{
    return translate("{translation["key"]}"{args})
}}
"""
            )

    return "\n".join(out) + "\n"


def get_arg_name_and_types(args: List[Variable]) -> str:
    if not args:
        return ""
    else:
        return (
            "args: {"
            + ", ".join(
                [f"{typescript_arg_name(arg)}: {arg_kind(arg)}" for arg in args]
            )
            + "}"
        )


def arg_kind(arg: Variable) -> str:
    if arg["kind"] in ("Int", "Float"):
        return "number"
    elif arg["kind"] == "Any":
        return "number | string"
    else:
        return "string"


def map_args_to_real_names(args: List[Variable]) -> str:
    return (
        "{"
        + ", ".join(
            [f'"{arg["name"]}": args.{typescript_arg_name(arg)}' for arg in args]
        )
        + "}"
    )


def get_args(args: List[Variable]) -> str:
    if not args:
        return ""
    else:
        for arg in args:
            if typescript_arg_name(arg) != arg["name"]:
                # we'll need to map variables to their fluent equiv
                return ", " + map_args_to_real_names(args)

        # variable names match, reference object instead
        return ", args"


def typescript_arg_name(arg: Variable) -> str:
    name = stringcase.camelcase(arg["name"].replace("-", "_"))
    if name == "new":
        return "new_"
    else:
        return name


def module_names() -> str:
    buf = "export enum ModuleName {\n"
    for module in modules:
        name = module["name"]
        upper = name.upper()
        buf += f'    {upper} = "{name}",\n'
    buf += "}\n"
    return buf


def write(outfile, out) -> None:
    open(outfile, "wb").write(
        (
            f"""// Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html

"""
            + out
        ).encode("utf8")
    )


write(translate_out, str(methods()))
write(modules_out, str(module_names()))
