"""
This script must be run from the root of the repository.

At a high level, the goal is to have a directory that emulates the full path structure of the
target machine which then gets packaged by tools that are only available on macOS.
"""

from __future__ import annotations

import argparse
import shutil
import subprocess
import sys
from pathlib import Path
from tempfile import TemporaryDirectory

REPO_DIR = Path.cwd()
ASSETS_DIR = Path(__file__).parent / "pkg"
IDENTIFIER = "org.python.hatch"
COMPONENT_PACKAGE_NAME = f"{IDENTIFIER}.pkg"
README = """\
<!DOCTYPE html>
<html>
<head></head>
<body>
  <p>This will install Hatch v{version} globally.</p>

  <p>For more information on installing and upgrading Hatch, see our <a href="https://hatch.pypa.io/latest/install/">Installation Guide</a>.</p>
</body>
</html>
"""


def run_command(command: list[str]) -> None:
    process = subprocess.run(command)  # noqa: PLW1510
    if process.returncode:
        sys.exit(process.returncode)


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("directory")
    parser.add_argument("--binary", required=True)
    parser.add_argument("--version", required=True)
    args = parser.parse_args()

    directory = Path(args.directory).absolute()
    staged_binary = Path(args.binary).absolute()
    binary_name = staged_binary.stem
    version = args.version

    with TemporaryDirectory() as d:
        temp_dir = Path(d)

        # This is where we assemble files required for builds
        resources_dir = temp_dir / "resources"
        shutil.copytree(str(ASSETS_DIR / "resources"), str(resources_dir))

        resources_dir.joinpath("README.html").write_text(README.format(version=version), encoding="utf-8")
        shutil.copy2(REPO_DIR / "LICENSE.txt", resources_dir)

        # This is what gets shipped to users starting at / (the root directory)
        root_dir = temp_dir / "root"
        root_dir.mkdir()

        # This is where we globally install Hatch. We choose to not offer per-user installs because we can't
        # find out where the location is and therefore cannot add to PATH usually. For more information, see:
        # https://github.com/aws/aws-cli/commit/f3c3eb8262786142a1712b6da5a1515ad9dc66c5
        relative_binary_dir = Path("usr", "local", binary_name, "bin")
        binary_dir = root_dir / relative_binary_dir
        binary_dir.mkdir(parents=True)
        shutil.copy2(staged_binary, binary_dir)

        # This is how we add the installation directory to PATH and is also what Go does,
        # although there are some caveats: https://apple.stackexchange.com/q/126725
        path_file = root_dir / "etc" / "paths.d" / binary_name
        path_file.parent.mkdir(parents=True)
        path_file.write_text(f"/{relative_binary_dir}\n", encoding="utf-8")

        # This is where we build the intermediate components
        components_dir = temp_dir / "components"
        components_dir.mkdir()

        run_command([
            "pkgbuild",
            "--root",
            str(root_dir),
            "--identifier",
            IDENTIFIER,
            "--version",
            version,
            "--install-location",
            "/",
            str(components_dir / COMPONENT_PACKAGE_NAME),
        ])

        # This is where we build the final artifact
        build_dir = temp_dir / "build"
        build_dir.mkdir()
        product_archive = build_dir / f"{binary_name}-universal.pkg"

        run_command([
            "productbuild",
            "--distribution",
            str(ASSETS_DIR / "distribution.xml"),
            "--resources",
            str(resources_dir),
            "--package-path",
            str(components_dir),
            str(product_archive),
        ])

        # Copy the final artifact to the target directory
        directory.mkdir(parents=True, exist_ok=True)
        shutil.copy2(product_archive, directory)


if __name__ == "__main__":
    main()
