#!/usr/bin/env python3
"""Script to update flag emojis and bridg emojis SVG files from Twemoji, and to
pull locale emoji descriptions form Unicode CLDR.
"""

import re
import json
import datetime
from pathlib import Path
from shutil import copyfile
import argparse
from xml.dom.minidom import parse

# Currently the script is in tools/torbrowser/
FIREFOX_ROOT = Path(__file__).parents[2]
SCRIPT_PATH = Path(__file__).relative_to(FIREFOX_ROOT)

LANGS = [
    "ar",
    "ca",
    "cs",
    "da",
    "de",
    "el",
    "en",
    "es",
    "fa",
    "fr",
    "ga",
    "he",
    "hu",
    "id",
    "is",
    "it",
    "ja",
    "ka",
    "ko",
    "lt",
    "mk",
    "ms",
    "my",
    # "nb",  # Empty file, currently!!
    "nl",
    "pl",
    "pt",
    "ro",
    "ru",
    "sv",
    "th",
    "tr",
    "uk",
    "vi",
    "zh-CN",  # zh, zh-hans
    "zh-TW",  # zh_Hant, zh-hant
]


def generated_message():
    """Get the message describing the generation script and time."""
    date = datetime.date.isoformat(datetime.datetime.utcnow())
    return f"Generated by {SCRIPT_PATH} on {date}"


def copy_emoji_svgs(emoji_codepoints, from_dir, to_dir):
    """Copy the emojis specified in `emoji_codepoints` in `from_dir` to
    `to_dir`. Each item in the `emoji_codepoints` list should be an
    iterable over an emoji's codepoints.
    """

    to_dir.mkdir(exist_ok=True)
    filename_set = set()
    for codepoint in emoji_codepoints:
        filename = codepoint + ".svg"
        filename_set.add(filename)
        src = from_dir / filename
        dst = to_dir / filename
        copyfile(src, dst)

    # Clean up old svgs.
    for file in to_dir.iterdir():
        if file.suffix != ".svg" or file.name in filename_set:
            continue
        file.unlink()

    with open(to_dir / "README.txt", "w", encoding="utf8") as file:
        file.write(generated_message())


def get_flag_codepoints(file):
    """Get the codepoint hex strings for all the region flags in the given
    `file`.
    """

    flag_line_regex = re.compile(
        r"^([0-9A-F]+) ([0-9A-F]+) +; RGI_Emoji_Flag_Sequence +;"
    )

    codepoints = []

    for line in file:
        match = flag_line_regex.match(line)
        if not match:
            continue
        # The emoji name includes a dash "-" between the codepoints.
        codepoints.append(f"{match.group(1).lower()}-{match.group(2).lower()}")

    return codepoints


def copy_flag_svgs(from_dir):
    """Copy the flag svgs from `from_dir`."""
    with open(
        FIREFOX_ROOT / "intl/icu/source/data/unidata/emoji-sequences.txt",
        "r",
        encoding="utf8",
    ) as file:
        flag_codepoints = get_flag_codepoints(file)

    flag_dest_dir = (
        FIREFOX_ROOT / "browser/components/torcircuit/content/tor-circuit-flags"
    )

    copy_emoji_svgs(flag_codepoints, from_dir, flag_dest_dir)


BRIDGE_DIR = FIREFOX_ROOT / "browser/components/torpreferences/content/bridgemoji"


def get_bridge_codepoints():
    """Get the list of codepoints for the bridge emojis as hex strings."""
    emoji_list = []
    with open(BRIDGE_DIR / "bridge-emojis.json", "r", encoding="utf8") as file:
        for emoji in json.load(file):
            if len(emoji) > 2 or (len(emoji) == 2 and ord(emoji[1]) != 0xFE0F):
                # U+FE0F is "VARIATION SELECTOR-16" is the emoji variant
                # selector (as opposed to the text selector U+FE0E). But this is
                # not included in the emoji's svg name or the annotations.
                raise ValueError(f"Unsupported emoji {emoji}: too many codepoints")
            # Only keep the first character's codepoint.
            emoji_list.append(f"{ord(emoji[0]):x}")

    return emoji_list


def copy_bridge_svgs(from_dir):
    """Copy the bridge svgs from `from_dir`."""
    bridge_codepoints = get_bridge_codepoints()

    bridge_dest_dir = BRIDGE_DIR / "svgs"

    copy_emoji_svgs(bridge_codepoints, from_dir, bridge_dest_dir)


def get_emoji_descriptions(emoji_codepoints, annotations_file):
    """Get the emoji descriptions for the given `emoji_strings` found in the
    given `annotation_file`.
    """
    descriptions = {}
    doc = parse(annotations_file)
    for annotation in doc.getElementsByTagName("annotation"):
        if annotation.getAttribute("type") != "tts":
            continue

        emoji = annotation.getAttribute("cp")
        if len(emoji) != 1:
            continue

        codepoint = f"{ord(emoji):x}"
        if codepoint not in emoji_codepoints:
            continue

        annotation.normalize()
        descriptions[codepoint] = annotation.firstChild.data

    missing = ",".join(
        chr(int(codepoint, 16))
        for codepoint in emoji_codepoints
        if codepoint not in descriptions
    )
    if missing:
        raise ValueError(
            f"Missing descriptions in {annotations_file.name} for {missing}"
        )

    return descriptions


def save_bridge_emoji_descriptions(from_dir):
    """Save the emoji descriptions found under the directory `from_dir`."""
    bridge_codepoints = get_bridge_codepoints()
    data = {"_comment": generated_message()}

    for lang in LANGS:
        if lang == "zh-CN":
            filename = "zh"
        elif lang == "zh-TW":
            filename = "zh_Hant"
        else:
            filename = lang
        with open(
            from_dir / f"common/annotations/{filename}.xml", "r", encoding="utf8"
        ) as file:
            data[lang] = get_emoji_descriptions(bridge_codepoints, file)

    with open(BRIDGE_DIR / "annotations.json", "w", encoding="utf8") as file:
        json.dump(data, file, ensure_ascii=False, indent=2)


parser = argparse.ArgumentParser(
    description="Update the emojis SVGs from Twemoji and their descriptions.\n"
    "SVGs can be extracted from  twe-svg.zip from "
    "https://github.com/mozilla/twemoji-colr\n"
    "The unicode CLDR repository is taken from "
    "https://github.com/unicode-org/cldr.git"
)
parser.add_argument(
    "--flag-svgs", metavar="<dir>", help="location of the flag emoji SVGs directory"
)
parser.add_argument(
    "--bridge-svgs", metavar="<dir>", help="location of the bridge emoji SVGs directory"
)
parser.add_argument(
    "--svgs", metavar="<dir>", help="defines both --bridge-svgs and --flag-svgs"
)
parser.add_argument(
    "--cldr", metavar="<dir>", help="location of the unicode CLDR repository"
)

parsed_args = parser.parse_args()

flag_svg_dir = parsed_args.flag_svgs or parsed_args.svgs
bridge_svg_dir = parsed_args.bridge_svgs or parsed_args.svgs
cldr_dir = parsed_args.cldr

if not flag_svg_dir and not bridge_svg_dir and not cldr_dir:
    print("No arguments")

if flag_svg_dir:
    copy_flag_svgs(Path(flag_svg_dir))

if bridge_svg_dir:
    copy_bridge_svgs(Path(bridge_svg_dir))

if cldr_dir:
    save_bridge_emoji_descriptions(Path(cldr_dir))
