#!/usr/bin/env python3

import argparse
import importlib
import inspect
import json
import re
import site
from functools import lru_cache
from pathlib import Path
from types import ModuleType
from typing import Any, Callable, Tuple, TypedDict, TypeVar

try:
    from typing import NotRequired
except ImportError:
    from typing_extensions import NotRequired

import yaml

from default_tranlsations import default_descriptions, default_translations

SECRET_FILENAME = "secrets.yaml"
SECRET_REGEX = re.compile(r"!secret\s(\w+)")

GENERICS = {
    "/doc/source/ics.md",
    "/doc/source/static.md",
}


BLACK_LIST = {
    *GENERICS,
    "/doc/source/multiple.md",
    "/doc/source/example.md",
}

START_COUNTRY_SECTION = "<!--Begin of country section-->"
END_COUNTRY_SECTION = "<!--End of country section-->"

START_SERVICE_SECTION = "<!--Begin of service section-->"
END_SERVICE_SECTION = "<!--End of service section-->"

LANGUAGES = ["en", "de", "it"]
ARG_TRANSLATIONS_TO_KEEP = ["calendar_title"]
ARG_DESCRIPTIONS_TO_KEEP = ["calendar_title"]
ARG_GENERAL_KEYS_TO_KEEP = ["title", "description"]

PACKAGE_DIR = (
    Path(__file__).resolve().parents[0]
    / "custom_components"
    / "waste_collection_schedule"
)
SOURCE_DIR = PACKAGE_DIR / "waste_collection_schedule" / "source"
DOC_URL_BASE = "https://github.com/mampfes/hacs_waste_collection_schedule/blob/master"

T = TypeVar("T")


def sort_param_dict(d: dict[str, T]) -> dict[str, T]:
    return dict(sorted(d.items()))


def sort_lang_param_dict(d: dict[str, dict[str, T]]) -> dict[str, dict[str, T]]:
    # sort lang
    d = dict(sorted(d.items()))
    # sort param
    for lang in d:
        d[lang] = sort_param_dict(d[lang])
    return d


class SourceInfo:
    def __init__(
        self,
        filename: str,
        module: str | None,
        title: str,
        url: str,
        country: str,
        params: list[str],
        extra_info_default_params: dict[str, Any] = {},
        custom_param_translation: dict[str, dict[str, str]] = {},
        custom_param_description: dict[str, dict[str, str]] = {},
        custom_howto: dict[str, str] = {},
    ):
        self._filename = filename
        self._module = module
        self._title = title
        self._url = url
        self._country = country
        self._params = sorted(params)
        self._extra_info_default_params = sort_param_dict(extra_info_default_params)

        self._custom_param_translation = default_translations(params)
        self._custom_param_translation.update(custom_param_translation)

        # sort alphabetically
        self._custom_param_translation = sort_lang_param_dict(
            self._custom_param_translation
        )

        self._custom_param_description = default_descriptions(params)
        self._custom_param_description.update(custom_param_description)
        self._custom_param_description = sort_lang_param_dict(
            self._custom_param_description
        )

        self._custom_howto = sort_param_dict(custom_howto)

        for k, v in custom_param_translation.items():
            if k not in LANGUAGES:
                print(
                    f"{self._filename} provided translation for non existing language {k}, You may want to use one of {LANGUAGES} or you need to add the language to LANGUAGES"
                )

            for parameter in v.keys():
                if parameter not in self._params:
                    print(
                        f"{self._filename} provided translation for non existing parameter {parameter}"
                    )

        for k, v in custom_param_description.items():
            if k not in LANGUAGES:
                print(
                    f"{self._filename} provided description for non existing language {k}, You may want to use one of {LANGUAGES} or you need to add the language to LANGUAGES"
                )

            for parameter in v.keys():
                if parameter not in self._params:
                    print(
                        f"{self._filename} provided description for non existing parameter {parameter}"
                    )

    def __repr__(self):
        return f"filename:{self._filename}, title:{self._title}, url:{self._url}, country:{self._country}, params:{self._params}, extra_info_default_params:{self._extra_info_default_params}, custom_param_translation:{self._custom_param_translation}"

    @property
    def filename(self):
        return self._filename

    @property
    def module(self):
        return self._module

    @property
    def title(self):
        return self._title

    @property
    def url(self):
        return self._url

    @property
    def country(self):
        return self._country

    @property
    def params(self):
        return self._params

    @property
    def extra_info_default_params(self):
        return self._extra_info_default_params

    @property
    def custom_param_translation(self):
        return self._custom_param_translation

    @property
    def custom_param_description(self):
        return self._custom_param_description

    @property
    def custom_howto(self):
        return self._custom_howto


class IcsSourceInfo(SourceInfo):
    def __init__(
        self,
        filename: str,
        title: str,
        url: str,
        country: str,
        limit_params: list[str],
        extra_info_default_params: dict[str, Any] = {},
        custom_howto: dict[str, str] = {},
    ):
        _, ics_sources = get_source_by_file("ics")
        ics_source = ics_sources[0]
        params = set(ics_source.params) - set(limit_params)
        translations = ics_source.custom_param_translation
        descriptions = ics_source.custom_param_description
        for translation in [*translations.values(), *descriptions.values()]:
            for param in list(translation.keys()):
                if param not in params:
                    translation.pop(param)

        super().__init__(
            filename=filename,
            module=None,
            title=title,
            url=url,
            country=country,
            params=list(params),
            extra_info_default_params=extra_info_default_params,
            custom_param_translation=translations,
            custom_param_description=descriptions,
            custom_howto=custom_howto,
        )


class Section:
    def __init__(self, section):
        self._section = section

    @property
    def start(self):
        return f"<!--Begin of {self._section} section-->"

    @property
    def end(self):
        return f"<!--End of {self._section} section-->"


class ExtraInfoDict(TypedDict):
    title: NotRequired[str]
    url: NotRequired[str]
    country: NotRequired[str]
    default_params: NotRequired[dict[str, Any]]


class IcsSourceData(TypedDict):
    title: str
    url: str
    description: NotRequired[str]
    howto: dict[str, str]
    country: NotRequired[str]
    default_params: NotRequired[dict[str, Any]]
    test_cases: dict[str, dict[str, Any]]
    extra_info: NotRequired[list[ExtraInfoDict]]


def split_camel_and_snake_case(s: str) -> list[str]:
    s = re.sub("([a-z0-9])([A-Z])", r"\1 \2", s)  # Split CamelCase
    return s.replace("_", " ").split()  # Split snake_case


def update_edpevent_se(modules: dict[str, ModuleType]):
    module = modules.get("edpevent_se")
    if not module:
        print("edpevent_se not found")
        return
    services = getattr(module, "SERVICE_PROVIDERS", {})

    str = ""
    for provider, data in sorted(services.items()):
        str += f'- `{provider}`: {data["title"]}\n'

    _patch_file("doc/source/edpevent_se.md", "service", str)


def main() -> None:
    sources: list[SourceInfo] = []

    sources += browse_sources()
    sources += browse_ics_yaml()

    # sort into countries
    country_code_map = make_country_code_map()
    countries: dict[str, list[SourceInfo]] = {}
    generics: list[SourceInfo] = []

    orphans: list[SourceInfo] = []
    for s in sources:
        if s.filename in GENERICS:
            generics.append(s)
        if s.filename in BLACK_LIST:
            continue  # skip

        # extract country code
        code = s.country
        if code in country_code_map:
            countries.setdefault(country_code_map[code]["name"], []).append(s)
        else:
            orphans.append(s)

    if len(orphans) > 0:
        print("Orphaned sources without country =========================")
        for o in orphans:
            print(o)

    update_json(countries, generics=generics)
    update_readme_md(countries)
    update_info_md(countries)


def browse_sources() -> list[SourceInfo]:
    """Browse all .py files in the `source` directory"""
    # add module directory to path
    site.addsitedir(str(PACKAGE_DIR))

    files = filter(
        lambda x: x != "__init__",
        map(lambda x: x.stem, SOURCE_DIR.glob("*.py")),
    )

    modules: dict[str, ModuleType] = {}
    sources: list[SourceInfo] = []

    # retrieve all data from sources
    for f in files:
        module, sources_out = get_source_by_file(f)
        modules[f] = module
        sources += sources_out

    update_awido_de(modules)
    update_ctrace_de(modules)
    update_citiesapps_com(modules)
    update_app_abfallplus_de(modules)
    update_abfallnavi_de(modules)
    update_edpevent_se(modules)

    return sources


@lru_cache(maxsize=None)
def get_source_by_file(file: str) -> tuple[ModuleType, list[SourceInfo]]:
    # iterate through all *.py files in waste_collection_schedule/source
    module = importlib.import_module(f"waste_collection_schedule.source.{file}")

    title = module.TITLE
    url = module.URL
    country = getattr(module, "COUNTRY", file.split("_")[-1])

    sig = inspect.signature(module.Source.__init__)
    params = [param.name for param in sig.parameters.values()]
    if "self" in params:
        params.remove("self")
    param_translations = getattr(module, "PARAM_TRANSLATIONS", {})
    param_descriptions = getattr(module, "PARAM_DESCRIPTIONS", {})
    howto = getattr(module, "HOW_TO_GET_ARGUMENTS_DESCRIPTION", {})

    filename = f"/doc/source/{file}.md"
    sources = []
    if title is not None:
        sources.append(
            SourceInfo(
                filename=filename,
                module=file,
                title=title,
                url=url,
                country=country,
                params=params,
                custom_param_translation=param_translations,
                custom_param_description=param_descriptions,
                custom_howto=howto,
            )
        )

    extra_info: list[ExtraInfoDict] | Callable[[], list[ExtraInfoDict]] = getattr(
        module, "EXTRA_INFO", []
    )
    if callable(extra_info):
        extra_info = extra_info()
    for e in extra_info:
        sources.append(
            SourceInfo(
                filename=filename,
                module=file,
                title=e.get("title", title),
                url=e.get("url", url),
                country=e.get("country", country),
                params=params,
                extra_info_default_params=e.get("default_params", {}),
                custom_howto=howto,
            )
        )
    return module, sources


def browse_ics_yaml() -> list[SourceInfo]:
    """Browse all .yaml files which are descriptions for the ICS source"""
    doc_dir = Path(__file__).resolve().parents[0] / "doc"
    yaml_dir = doc_dir / "ics" / "yaml"
    md_dir = doc_dir / "ics"

    files = yaml_dir.glob("*.yaml")
    sources: list[SourceInfo] = []
    for f in files:
        with open(f, encoding="utf-8") as stream:
            # write markdown file
            filename = (md_dir / f.name).with_suffix(".md")
            data: IcsSourceData = yaml.safe_load(stream)

            howto = data.get("howto", {})
            if isinstance(data["howto"], str):
                print(
                    f"howto in {f} is a string, it should be a dictionary with language keys"
                )
                data["howto"] = {"en": howto}

            write_ics_md_file(filename, data)
            howto = data.get("howto", {})
            if isinstance(howto, str):
                print(
                    f"howto in {f} is a string, it should be a dictionary with language keys"
                )
                howto = {"en": howto}

            country = data.get("country", f.stem.split("_")[-1])
            # extract country code
            sources.append(
                IcsSourceInfo(
                    filename=f"/doc/ics/{filename.name}",
                    title=data["title"],
                    url=data["url"],
                    country=country,
                    limit_params=[],
                    extra_info_default_params=data.get("default_params", {}),
                    custom_howto=howto,
                )
            )
            if "extra_info" in data:
                for e in data["extra_info"]:
                    sources.append(
                        IcsSourceInfo(
                            filename=f"/doc/ics/{filename.name}",
                            title=e.get("title", data["title"]),
                            url=e.get("url", data["url"]),
                            country=e.get("country", country),
                            limit_params=[],
                            extra_info_default_params=data.get("default_params", {}),
                            custom_howto=howto,
                        )
                    )

    update_ics_md(sources)

    return sources


def write_ics_md_file(filename: Path, data: IcsSourceData) -> None:
    """Write a markdown file for a ICS .yaml file"""
    if not "en" in data["howto"]:
        print(
            f"howto in {filename} does not contain an english translation, please add one"
        )
        return

    md = f"# {data['title']}\n"
    md += "\n"
    md += f"{data['title']} is supported by the generic [ICS](/doc/source/ics.md) source. For all available configuration options, please refer to the source description.\n"
    md += "\n"
    if "description" in data:
        md += f"{data['description']}\n"
    md += "\n"
    md += "## How to get the configuration arguments\n"
    md += "\n"
    md += f"{data['howto']['en']}"
    md += "\n"
    md += "## Examples\n"
    md += "\n"
    for title, tc in data["test_cases"].items():
        md += f"### {title}\n"
        md += "\n"
        md += "```yaml\n"
        md += "waste_collection_schedule:\n"
        md += "  sources:\n"
        md += "    - name: ics\n"
        md += "      args:\n"
        md += multiline_indent(yaml.dump(tc).rstrip("\n"), 8) + "\n"
        md += "```\n"
        # md += "\n"
    with open(filename, "w", encoding="utf-8") as f:
        f.write(md)


def update_ics_md(sources: list[SourceInfo]):
    country_code_map = make_country_code_map()
    countries: dict = {}

    for s in sources:
        if s.filename in BLACK_LIST:
            continue  # skip

        # extract country code
        code = s.country
        if code in country_code_map:
            countries.setdefault(country_code_map[code]["name"], []).append(s)

    str = ""
    for country in sorted(countries):
        str += f"### {country}\n"
        str += "\n"

        for e in sorted(
            countries[country],
            key=lambda e: (e.title.lower(), beautify_url(e.url), e.filename),
        ):
            str += f"- [{e.title}]({e.filename}) / {beautify_url(e.url)}\n"

        str += "\n"

    _patch_file("doc/source/ics.md", "service", str)


def multiline_indent(s, numspaces):
    """Indent all lines within the given string by <numspace> spaces"""
    lines = [(numspaces * " ") + line for line in s.split("\n")]
    return "\n".join(lines)


def beautify_url(url):
    if url is None:
        return ""
    url = url.removesuffix("/")
    url = url.removeprefix("http://")
    url = url.removeprefix("https://")
    url = url.removeprefix("www.")
    return url


def update_sources_json(countries: dict[str, list[SourceInfo]]) -> None:
    output: dict[str, list[dict[str, str | dict[str, Any]]]] = {}
    for country in sorted(countries):
        output[country] = []
        for e in sorted(
            countries[country],
            key=lambda e: (e.title.lower(), beautify_url(e.url), e.filename),
        ):
            module = e.module if e.module is not None else "ics"
            id = e.filename.split("/")[-1].removesuffix(".md")
            if id != module:
                id = f"{module}_{id}"

            output[country].append(
                {
                    "title": e.title,
                    "module": module,
                    "default_params": e.extra_info_default_params,
                    "id": id,
                }
            )
    with open(
        "custom_components/waste_collection_schedule/sources.json",
        "w",
        encoding="utf-8",
    ) as f:
        f.write(json.dumps(output, indent=2))


def get_custom_translations(
    countries: dict[str, list[SourceInfo]]
) -> Tuple[
    dict[str, dict[str, dict[str, str | None]]],
    dict[str, dict[str, dict[str, str | None]]],
    dict[str, dict[str, str | None]],
    dict[str, str],
]:
    """gets all parameters and its custom translations for all languages

    Args:
        countries (dict[str, list[SourceInfo]]):

    Returns:
        Tuple[dict[str, dict[str, dict[str, str | None]]], dict[str, dict[str, dict[str, str | None]]]]: Param translation dict[MODULE][PARAM][LANG][TRANSLATION|None], Param Description: dict[MODULE][PARAM][LANG][DESCRIPTION|None], Source howto: dict[MODULE][LANG][HOWTO|None], Source doc url: dict[MODULE][URL]
    """
    param_translations: dict[str, dict[str, dict[str, str | None]]] = {}
    param_descriptions: dict[str, dict[str, dict[str, str | None]]] = {}
    source_howto: dict[str, dict[str, str | None]] = {}
    source_doc_url: dict[str, str] = {}

    for country in sorted(countries):
        for e in sorted(
            countries[country],
            key=lambda e: (e.title.lower(), beautify_url(e.url), e.filename),
        ):
            module = e.module
            if e.module is None:  # ICS source
                module = "ics_" + e.filename.split("/")[-1].removesuffix(".md")

            source_doc_url[module] = DOC_URL_BASE + e.filename

            if not module in param_translations:
                param_translations[module] = {}
            if not module in param_descriptions:
                param_descriptions[module] = {}

            for param in sorted(e.params):
                if param not in param_translations[module]:
                    param_translations[module][param] = {}
                if param not in param_descriptions[module]:
                    param_descriptions[module][param] = {}

            for lang, translations in e.custom_param_translation.items():
                for param, translation in translations.items():
                    param_translations[module][param][lang] = translation

            for lang, descriptions in e.custom_param_description.items():
                for param, description in descriptions.items():
                    param_descriptions[module][param][lang] = description

            source_howto[module] = e.custom_howto

    return param_translations, param_descriptions, source_howto, source_doc_url


def update_json(
    countries: dict[str, list[SourceInfo]], generics: list[SourceInfo] = []
):
    countries = countries.copy()
    countries["Generic"] = generics
    update_sources_json(countries)
    (
        param_translations,
        param_descriptions,
        source_howto,
        source_doc_url,
    ) = get_custom_translations(countries)

    for lang in LANGUAGES:
        tranlation_file = (
            f"custom_components/waste_collection_schedule/translations/{lang}.json"
        )
        if not Path(tranlation_file).exists():
            print(f"Translation file {tranlation_file} not found")
            continue

        with open(
            tranlation_file,
            encoding="utf-8",
        ) as f:
            translations = json.load(f)

        translation_for_all = {}
        description_for_all_args = {}
        description_for_all_reconfigure = {}

        keys_for_all_args = {}
        keys_for_all_reconfigure = {}

        for key, value in translations["config"]["step"]["args"]["data"].items():
            if key in ARG_TRANSLATIONS_TO_KEEP:
                translation_for_all[key] = value

        for key, value in (
            translations["config"]["step"]["args"].get("data_description", {}).items()
        ):
            if key in ARG_DESCRIPTIONS_TO_KEEP:
                description_for_all_args[key] = value
        for key, value in (
            translations["config"]["step"]["reconfigure"]
            .get("data_description", {})
            .items()
        ):
            if key in ARG_DESCRIPTIONS_TO_KEEP:
                description_for_all_reconfigure[key] = value

        for key, value in translations["config"]["step"]["args"].items():
            if key in ARG_GENERAL_KEYS_TO_KEEP:
                keys_for_all_args[key] = value
        for key, value in translations["config"]["step"]["reconfigure"].items():
            if key in ARG_GENERAL_KEYS_TO_KEEP:
                keys_for_all_reconfigure[key] = value

        for module, module_params in param_translations.items():
            translations["config"]["step"][f"args_{module}"] = keys_for_all_args.copy()
            translations["config"]["step"][
                f"reconfigure_{module}"
            ] = keys_for_all_reconfigure.copy()

            translations["config"]["step"][f"args_{module}"][
                "data"
            ] = translation_for_all.copy()
            translations["config"]["step"][f"reconfigure_{module}"][
                "data"
            ] = translation_for_all.copy()

            translations["config"]["step"][f"args_{module}"][
                "data_description"
            ] = description_for_all_args.copy()
            translations["config"]["step"][f"reconfigure_{module}"][
                "data_description"
            ] = description_for_all_reconfigure.copy()

            for param, languages in module_params.items():
                if languages.get(lang, None) is None:
                    languages[lang] = " ".join(
                        [s.capitalize() for s in split_camel_and_snake_case(param)]
                    )
                translations["config"]["step"][f"args_{module}"]["data"][
                    param
                ] = languages[lang]
                translations["config"]["step"][f"reconfigure_{module}"]["data"][
                    param
                ] = languages[lang]

            for param, languages in param_descriptions.get(module, {}).items():
                if languages.get(lang, None) is None:
                    continue
                translations["config"]["step"][f"args_{module}"]["data_description"][
                    param
                ] = languages[lang]
                translations["config"]["step"][f"reconfigure_{module}"][
                    "data_description"
                ][param] = languages[lang]

            module_howto = source_howto.get(module, {})

            howto_str = (
                module_howto.get(lang, None) or module_howto.get("en", None) or ""
            )
            howto_str = format_howto(howto_str)
            translations["config"]["step"][f"args_{module}"][
                "description"
            ] = translations["config"]["step"]["args"]["description"].format(
                howto=howto_str, docs_url=source_doc_url.get(module, "")
            )
            translations["config"]["step"][f"reconfigure_{module}"][
                "description"
            ] = translations["config"]["step"]["reconfigure"]["description"].format(
                howto=howto_str, docs_url=source_doc_url.get(module, "")
            )

        with open(
            tranlation_file,
            "w",
            encoding="utf-8",
        ) as f:
            json.dump(translations, f, indent=2, ensure_ascii=False)


def format_howto(howto: str) -> str:
    if not howto:
        return ""

    howto = "\n\n" + howto + "\n\n"
    new_howto = ""
    code_opened = False
    code_buffer = ""
    do_not_code = False
    for c in howto:
        match c:
            case "`":
                code_buffer += c if not do_not_code else "'"
                code_opened = not code_opened
                if not code_opened:
                    do_not_code = False
            case "{":
                code_buffer += "&#123;"
                do_not_code = code_opened
            case "}":
                code_buffer += "&#125;"
                do_not_code = code_opened
            case "<":
                code_buffer += "&lt;"
                do_not_code = code_opened
            case ">":
                code_buffer += "&gt;"
                do_not_code = code_opened
            case _:
                code_buffer += c
        if not code_opened:
            new_howto += code_buffer
            code_buffer = ""
        if code_opened and do_not_code:
            code_buffer = code_buffer.replace("`", "'")

    # REGEX replace &lt;https://www.example.com&gt; with https://www.example.com
    new_howto = re.sub(r"&lt;(https?://[^>]+?)&gt;", r"\1", new_howto)
    new_howto = new_howto.replace("``'", "").replace("'``", "")

    return new_howto


def update_readme_md(countries: dict[str, list[SourceInfo]]):
    # generate country list
    str = ""
    for country in sorted(countries):
        str += "<details>\n"
        str += f"<summary>{country}</summary>\n"
        str += "\n"

        for e in sorted(
            countries[country],
            key=lambda e: (e.title.lower(), beautify_url(e.url), e.filename),
        ):
            # print(f"  {e.title} - {beautify_url(e.url)}")
            str += f"- [{e.title}]({e.filename}) / {beautify_url(e.url)}\n"

        str += "</details>\n"
        str += "\n"

    _patch_file("README.md", "country", str)


def update_info_md(countries: dict[str, list[SourceInfo]]):
    # generate country list
    str = ""
    for country in sorted(countries):
        str += f"| {country} | "
        str += ", ".join(
            [
                e.title
                for e in sorted(
                    countries[country],
                    key=lambda e: (e.title.lower(), beautify_url(e.url), e.filename),
                )
            ]
        )
        str += " |\n"

    _patch_file("info.md", "country", str)


def update_awido_de(modules: dict[str, ModuleType]):
    module = modules.get("awido_de")
    if not module:
        print("awido_de not found")
        return
    services = getattr(module, "SERVICE_MAP", [])

    str = ""
    for service in sorted(services, key=lambda s: s["service_id"]):
        str += f'- `{service["service_id"]}`: {service["title"]}\n'

    _patch_file("doc/source/awido_de.md", "service", str)


def update_ctrace_de(modules: dict[str, ModuleType]):
    module = modules.get("c_trace_de")
    if not module:
        print("ctrace_de not found")
        return
    services = getattr(module, "SERVICE_MAP", {})

    str = "|Municipality|service|\n|-|-|\n"
    for service in sorted(
        services.keys(), key=lambda service: services[service]["title"]
    ):
        str += f'| {services[service]["title"]} | `{service}` |\n'

    _patch_file("doc/source/c_trace_de.md", "service", str)


def update_citiesapps_com(modules: dict[str, ModuleType]):
    module = modules.get("citiesapps_com")
    if not module:
        print("citiesapps_com not found")
        return
    services = getattr(module, "SERVICE_MAP", [])

    str = "|City|Website|\n|-|-|\n"
    for service in sorted(services, key=lambda service: service["title"]):
        str += f'| {service["title"]} | [{beautify_url(service["url"])}]({service["url"]}) |\n'

    _patch_file("doc/source/citiesapps_com.md", "service", str)


def update_app_abfallplus_de(modules: dict[str, ModuleType]):
    module = modules.get("app_abfallplus_de")
    if not module:
        print("app_abfallplus_de not found")
        return
    services = getattr(module, "SUPPORTED_SERVICES", {})

    str = "|app_id|supported regions|\n|-|-|\n"
    for app_id, region in services.items():
        regions = ", ".join(region)
        str += f"| {app_id} | {regions} |\n"

    _patch_file("doc/source/app_abfallplus_de.md", "service", str)


def update_abfallnavi_de(modules: dict[str, ModuleType]):
    module = modules.get("abfallnavi_de")
    if not module:
        print("app_abfallplus_de not found")
        return
    services = getattr(module, "SERVICE_DOMAINS", {})

    str = "|Region|service|\n|-|-|\n"
    for region in services:
        str += f"| {region['title']} | {region['service_id']} |\n"

    _patch_file("doc/source/abfallnavi_de.md", "service", str)


def _patch_file(filename, section_id, str):
    # read entire file
    with open(filename, encoding="utf-8") as f:
        md = f.read()

    section = Section(section_id)

    # find beginning and end of country section
    start_pos = md.index(section.start) + len(section.start) + 1
    end_pos = md.index(section.end)

    md = md[:start_pos] + str + md[end_pos:]

    # write entire file
    with open(filename, "w", encoding="utf-8") as f:
        f.write(md)


def make_country_code_map():
    return {x["code"]: x for x in COUNTRYCODES}


COUNTRYCODES = [
    {
        "code": "au",
        "name": "Australia",
    },
    {
        "code": "at",
        "name": "Austria",
    },
    {
        "code": "be",
        "name": "Belgium",
    },
    {
        "code": "ca",
        "name": "Canada",
    },
    {
        "code": "cz",
        "name": "Czech Republic",
    },
    {
        "code": "de",
        "name": "Germany",
    },
    {
        "code": "dk",
        "name": "Denmark",
    },
    {
        "code": "hamburg",
        "name": "Germany",
    },
    {
        "code": "hu",
        "name": "Hungary",
    },
    {
        "code": "it",
        "name": "Italy",
    },
    {
        "code": "lt",
        "name": "Lithuania",
    },
    {
        "code": "lu",
        "name": "Luxembourg",
    },
    {
        "code": "nl",
        "name": "Netherlands",
    },
    {
        "code": "nz",
        "name": "New Zealand",
    },
    {
        "code": "no",
        "name": "Norway",
    },
    {
        "code": "pl",
        "name": "Poland",
    },
    {
        "code": "se",
        "name": "Sweden",
    },
    {
        "code": "si",
        "name": "Slovenia",
    },
    {
        "code": "ch",
        "name": "Switzerland",
    },
    {
        "code": "us",
        "name": "United States of America",
    },
    {
        "code": "uk",
        "name": "United Kingdom",
    },
    {
        "code": "fr",
        "name": "France",
    },
    {
        "code": "fi",
        "name": "Finland",
    },
]


if __name__ == "__main__":
    main()
