#!/usr/bin/python3
import os
import subprocess
import sys
from typing import Union
from collections.abc import Mapping

SOURCE_ROOT = os.path.dirname(os.path.dirname(__file__))

inc_path = os.path.join(SOURCE_ROOT, "src")
sys.path.insert(0, inc_path)

from debputy.util import _error

from debputy.lsp.lsp_reference_keyword import LSP_DATA_DOMAIN

from debputy.lsp.languages.lsp_debian_control import (
    dctrl_substvars_metadata,
    SubstvarMetadata,
    dctrl_variables_metadata_basename,
)
from debputy.lsp.languages.lsp_debian_watch import (
    VariableMetadata,
    dwatch_variables_metadata_basename,
    dwatch_variables_metadata,
)
from debputy.lsp.lsp_debian_control_reference_data import (
    TRANSLATABLE_DEB822_FILE_METADATA,
    lsp_reference_data_dir,
    Deb822KnownField,
)

try:
    from polib import pofile, POEntry, POFile
except ImportError:
    _error("This script needs polib (python3-polib)")


def strip_source_root(filename: str) -> str:
    if filename.startswith(SOURCE_ROOT + "/"):
        filename = filename[len(SOURCE_ROOT) + 1 :]
    return filename


def pot_file_from_template(raw_template: str) -> POFile:
    pot_file = pofile(raw_template, encoding="utf-8")
    pot_file.clear()
    pot_file.metadata["Content-Type"] = "text/plain; charset=utf-8"
    return pot_file


def generate_po_from_docs(
    pot_file: POFile,
    filename: str,
    msgctxt: str,
    topic: str,
    synopsis: str,
    hover_doc: str,
) -> None:
    if synopsis:
        pot_file.append(
            POEntry(
                msgctxt=msgctxt,
                msgid=synopsis,
                occurrences=[(filename, 0)],
                comment=f"[Synopsis] One-line description of {topic} [Plaintext]. Shown with completion (etc.)",
                flags=[],
            )
        )
    if hover_doc and hover_doc != synopsis:
        pot_file.append(
            POEntry(
                msgctxt=msgctxt,
                msgid=hover_doc,
                occurrences=[(filename, 0)],
                comment=f"[Hover Doc] Extended description of {topic} [Markdown]. Shown in hover docs (etc.)",
                flags=["python-brace-format"],
            )
        )


def generate_lsp_data_pot(raw_template: str) -> POFile:
    pot_file = pot_file_from_template(raw_template)

    for file_metadata_constructor in TRANSLATABLE_DEB822_FILE_METADATA:
        file_metadata = file_metadata_constructor()
        name = file_metadata.reference_data_basename
        filename = strip_source_root(os.path.join(lsp_reference_data_dir(), name))

        for stanza in file_metadata.stanza_types():
            field: Deb822KnownField
            for field in stanza.stanza_fields.values():
                field_synopsis = field.synopsis
                field_hover_doc = field.long_description
                known_values = field.known_values

                generate_po_from_docs(
                    pot_file,
                    filename,
                    f"Stanza:{stanza.stanza_type_name}|Field:{field.name}",
                    "the field itself",
                    field_synopsis,
                    field_hover_doc,
                )

                if known_values:
                    for keyword in known_values.values():
                        kw_synopsis = keyword.synopsis
                        kw_hover_doc = keyword.long_description

                        generate_po_from_docs(
                            pot_file,
                            filename,
                            f"Stanza:{stanza.stanza_type_name}|Field:{field.name}",
                            f'the value "{keyword.value}"',
                            kw_synopsis,
                            kw_hover_doc,
                        )

    for filename, variables in [
        (
            strip_source_root(
                os.path.join(
                    lsp_reference_data_dir(), dctrl_variables_metadata_basename()
                )
            ),
            dctrl_substvars_metadata(),
        ),
        (
            strip_source_root(
                os.path.join(
                    lsp_reference_data_dir(), dwatch_variables_metadata_basename()
                )
            ),
            dwatch_variables_metadata(),
        ),
    ]:
        _generate_variable_po(pot_file, filename, variables)

    return pot_file


def _generate_variable_po(
    pot_file: POFile,
    variable_metadata_file: str,
    variables: Mapping[str, SubstvarMetadata | VariableMetadata],
) -> None:
    for variable in variables.values():
        generate_po_from_docs(
            pot_file,
            variable_metadata_file,
            f"Variable:{variable.name}",
            f'the variable "{variable.name}"',
            variable.synopsis,
            variable.description,
        )


def main() -> None:
    os.environ["TZ"] = "UTC"
    output_dir = os.path.join(SOURCE_ROOT, "po")

    try:
        debputy_version = (
            subprocess.check_output(
                [os.path.join(SOURCE_ROOT, "debputy.sh"), "--version"]
            )
            .decode("utf-8")
            .strip()
        )
    except subprocess.CalledProcessError:
        debputy_version = "VERSION"

    # We are just doing this for the header (metadata entry)
    raw_template = subprocess.check_output(
        [
            "xgettext",
            "-L",
            "Python",
            "--package-name=debputy",
            f"--package-version={debputy_version}",
            "--from-code=utf-8",
            "--foreign-user",
            "--msgid-bugs-address=https://salsa.debian.org/debian/debputy/-/issues/",
            "/dev/stdin",
            "-o-",
        ],
        input=b'_("foo")',
    ).decode("utf-8")
    lsp_data_pot = generate_lsp_data_pot(raw_template)

    output_name = os.path.join(output_dir, LSP_DATA_DOMAIN, "messages.pot")

    with open(output_name, "w", encoding="utf-8") as fd:
        fd.write(str(lsp_data_pot))
    print(f"Generated {output_name}")


if __name__ == "__main__":
    main()
