from __future__ import annotations

import argparse
import hashlib
import subprocess
import sys
from datetime import datetime, timezone
from pathlib import Path

import defusedxml.ElementTree as ET

from dissect.target.tools.utils.cli import catch_sigpipe

TEMPLATE = """\
# This file is generated by target-build-winzones
# Do not edit manually, see ``build_winzones.py``.
#
# Generated on:         {timestamp}
# Source SHA1 hash:     {hash}
# Number of timezones:  {count}
# References:           https://cldr.unicode.org/
#                       https://github.com/unicode-org/cldr/blob/main/common/supplemental/windowsZones.xml
from __future__ import annotations

WINDOWS_ZONE_MAP = {zones}
"""


def parse_winzones_xml(path: Path) -> str:
    """Attempt to parse a Unicode ``WinZones.xml`` document."""
    content = path.read_bytes()
    hash = hashlib.sha1(content).hexdigest()

    zones = {
        child.attrib["other"]: child.attrib["type"]
        for child in ET.fromstring(content.decode()).findall("./windowsZones/mapTimezones/mapZone")
        if child.attrib["territory"] == "001"
    }

    # Change 'Etc/UTC' to 'UTC' to be consistent across operating systems.
    zones["UTC"] = "UTC"

    return TEMPLATE.format(
        timestamp=datetime.now(tz=timezone.utc),
        hash=hash,
        count=len(zones),
        zones=zones,
    )


@catch_sigpipe
def main() -> int:
    help_formatter = argparse.ArgumentDefaultsHelpFormatter
    parser = argparse.ArgumentParser(
        description="target-build-winzones",
        fromfile_prefix_chars="@",
        formatter_class=help_formatter,
    )
    parser.add_argument("path", metavar="PATH", type=Path, help="path to windowsZones.xml file")
    parser.add_argument(
        "--output", "-o", type=Path, help="optional alternative output path for generated types document"
    )
    parser.add_argument("--format", action="store_true", default=False, help="format output using ruff")
    args = parser.parse_args()

    if not args.path.is_file():
        print(f"Provided file does not exist: {args.path}")
        return 1

    output = (args.output or Path(__file__).parents[1].joinpath("helpers/locale/windows_zones.py")).resolve()

    if not output.parent.is_dir():
        print(f"Output path parent directory {output.parent} does not exist")
        return 1

    try:
        content = parse_winzones_xml(args.path)
    except Exception as e:
        print(f"Exception while generating output: {e!s}")
        return 1

    try:
        output.write_text(content)
    except Exception as e:
        print(f"Exception while writing output to {output!s}: {e!s}")
        return 1

    if args.format:
        subprocess.run(["ruff", "format", output], capture_output=True)
        subprocess.run(["ruff", "check", "--fix", "--unsafe-fixes", output], capture_output=True)

    return 0


if __name__ == "__main__":
    sys.exit(main())
