"""Generate Estonian and English pages from the Russian source in public/.

Translation IDs are stable indices in source-ru.json. Unknown Russian copy stops
this build instead of silently publishing an untranslated medical description.
Run npm run localize to regenerate and format the resulting HTML together.
"""
from pathlib import Path
from html.parser import HTMLParser
import html
import json
import re

PROJECT_ROOT = Path(__file__).resolve().parent
SITE_DIRECTORY = PROJECT_ROOT / "public"
TRANSLATION_DIRECTORY = PROJECT_ROOT / "locales"
TARGET_LANGUAGES = ("et", "en")
PORTALS = {
    "ru": "https://connectedserver.eu/ConnectedOnlineX/default.aspx?key=vylyh43r&lang=ru",
    "et": "https://connectedserver.eu/ConnectedOnlineX/default.aspx?key=gajlfe2U&lang=et",
    "en": "https://connectedserver.eu/ConnectedOnlineX/default.aspx?key=vRYhjcQ9&lang=en",
}
EXTRA_TRANSLATIONS = {
    "et": {"Email": "E-post", "name@example.com": "nimi@example.com", "ENTHELOS OÜ": "ENTHELOS OÜ"},
    "en": {},
}


def normalize_whitespace(value):
    """Ignore formatter line wraps when matching approved translation text."""
    return " ".join(value.split())


def load_translations():
    source_texts = json.loads((TRANSLATION_DIRECTORY / "source-ru.json").read_text(encoding="utf-8"))
    translations_by_id = {}
    for translation_file in sorted(TRANSLATION_DIRECTORY.glob("translations-*.txt")):
        for line in translation_file.read_text(encoding="utf-8").splitlines():
            if not line.strip():
                continue
            translation_id, estonian, english = line.split("|", 2)
            translation_id = int(translation_id)
            assert translation_id not in translations_by_id, f"Duplicate translation {translation_id}"
            translations_by_id[translation_id] = {"et": estonian, "en": english}
    assert set(translations_by_id) == set(range(len(source_texts))), "Incomplete translations"
    lookup = {
        language: {
            normalize_whitespace(source_text): translations_by_id[index][language]
            for index, source_text in enumerate(source_texts)
        }
        for language in TARGET_LANGUAGES
    }
    # This historical source contained an editorial note, removed from visible copy.
    editorial_note = " (Эта информация должна быть размещена на первой странице)"
    for index, source_text in enumerate(source_texts):
        if editorial_note in source_text:
            for language in TARGET_LANGUAGES:
                lookup[language][normalize_whitespace(source_text.replace(editorial_note, ""))] = translations_by_id[index][language]
    return lookup


def localized_url(language, route):
    return ("" if language == "ru" else "/" + language) + route


def language_switcher(language, route):
    label = {"ru": "Язык сайта", "et": "Veebilehe keel", "en": "Website language"}[language]
    links = []
    for target_language in ("ru", *TARGET_LANGUAGES):
        current_attribute = ' aria-current="page"' if target_language == language else ""
        links.append(
            f'<a href="{localized_url(target_language, route)}" lang="{target_language}" '
            f'hreflang="{target_language}"{current_attribute}>{target_language.upper()}</a>'
        )
    return f'<div class="language-switch" role="group" aria-label="{label}">{"".join(links)}</div>'


def alternate_links(route):
    return "".join(
        f'<link rel="alternate" hreflang="{language}" href="{localized_url(language, route)}">'
        for language in ("ru", *TARGET_LANGUAGES)
    )


class PageTranslator(HTMLParser):
    """Translate visible copy and selected attributes, retaining URLs and SVG markup."""

    def __init__(self, language, lookup, routes):
        super().__init__(convert_charrefs=True)
        self.language = language
        self.lookup = lookup[language]
        self.routes = routes
        self.output = []
        self.missing_translations = set()

    def translate_text(self, value):
        key = normalize_whitespace(value)
        translation = self.lookup.get(key, EXTRA_TRANSLATIONS[self.language].get(key))
        if translation is not None:
            # Preserve boundary whitespace around inline elements, not source line wraps.
            return value[:len(value) - len(value.lstrip())] + translation + value[len(value.rstrip()):]
        if re.search("[А-Яа-яЁё]", value):
            self.missing_translations.add(value)
        return value

    def handle_decl(self, declaration):
        self.output.append("<!" + declaration + ">")

    def handle_comment(self, comment):
        self.output.append("<!--" + comment + "-->")

    def handle_starttag(self, tag, attributes):
        rendered_attributes = []
        for name, value in attributes:
            if value is None:
                rendered_attributes.append(name)
                continue
            if name in ("content", "alt", "aria-label", "placeholder"):
                value = self.translate_text(value)
            if tag == "html" and name == "lang":
                value = self.language
            if name == "href":
                if value in self.routes:
                    value = localized_url(self.language, value)
                elif value.startswith("https://connectedserver.eu/ConnectedOnlineX/"):
                    value = PORTALS[self.language]
            rendered_attributes.append(name + '="' + html.escape(value, quote=True) + '"')
        attributes_html = " " + " ".join(rendered_attributes) if rendered_attributes else ""
        self.output.append("<" + tag + attributes_html + ">")

    def handle_startendtag(self, tag, attributes):
        self.handle_starttag(tag, attributes)
        self.output[-1] = self.output[-1][:-1] + "/>"

    def handle_endtag(self, tag):
        self.output.append("</" + tag + ">")

    def handle_data(self, value):
        self.output.append(html.escape(self.translate_text(value), quote=False))


def add_language_navigation(page_html, language, route):
    page_html = re.sub(
        r'<details\b(?=[^>]*class="menu")[^>]*>',
        lambda match: language_switcher(language, route) + match.group(),
        page_html,
        count=1,
    )
    return re.sub(r"</head\s*>", lambda match: alternate_links(route) + "</head>", page_html)


def main():
    lookup = load_translations()
    russian_pages = [
        page for page in SITE_DIRECTORY.rglob("index.html")
        if page.relative_to(SITE_DIRECTORY).parts[0] not in TARGET_LANGUAGES
    ]
    routes = {"/" + page.parent.relative_to(SITE_DIRECTORY).as_posix().strip(".").strip("/") + "/" for page in russian_pages}
    routes.discard("//")
    routes.add("/")
    for source_page in russian_pages:
        relative_directory = source_page.parent.relative_to(SITE_DIRECTORY).as_posix()
        route = "/" if relative_directory == "." else "/" + relative_directory + "/"
        source_html = source_page.read_text(encoding="utf-8")
        # Generated SEO contains language-specific copy and JSON-LD, not translation source.
        source_html = re.sub(r"<!-- SEO:START -->.*?<!-- SEO:END -->", "", source_html, flags=re.S)
        # Remove generated navigation before re-adding it; support formatted multiline HTML.
        source_html = re.sub(r'<div\b[^>]*class="language-switch"[^>]*>.*?</div\s*>', "", source_html, flags=re.S)
        source_html = re.sub(r'<link\b(?=[^>]*rel="alternate")[^>]*>', "", source_html)
        for language in TARGET_LANGUAGES:
            translator = PageTranslator(language, lookup, routes)
            translator.feed(source_html)
            assert not translator.missing_translations, (source_page, translator.missing_translations)
            translated_html = re.sub(r"<(h2|p)>\s*</\1>", "", "".join(translator.output))
            if language == "et":
                translated_html = re.sub(r"erameditsiini-\s*<br\s*/?>\s*kliinik", "erakliinik", translated_html)
                translated_html = re.sub(r"Meditsiini-\s*<br\s*/?>\s*teenused", "Meditsiinilised<br>teenused", translated_html)
            destination = SITE_DIRECTORY / language / source_page.relative_to(SITE_DIRECTORY)
            destination.parent.mkdir(parents=True, exist_ok=True)
            destination.write_text(add_language_navigation(translated_html, language, route), encoding="utf-8")
        source_page.write_text(add_language_navigation(source_html, "ru", route), encoding="utf-8")
    for language in ("ru", *TARGET_LANGUAGES):
        language_directory = SITE_DIRECTORY if language == "ru" else SITE_DIRECTORY / language
        (language_directory / "404.html").write_text((language_directory / "404/index.html").read_text(encoding="utf-8"), encoding="utf-8")
    print(f"Localized {len(russian_pages)} pages into Estonian and English.")


if __name__ == "__main__":
    main()
