#!/usr/bin/env python3
"""Dependency-free user installer for the msdev client and daemon."""

from __future__ import annotations

import argparse
import os
import shutil
import sys
from pathlib import Path


def install(prefix: Path) -> None:
    source = Path(__file__).resolve().parent / "src" / "msdev"
    if not source.is_dir():
        raise RuntimeError(f"msdev source package not found: {source}")

    prefix = prefix.expanduser().resolve()
    package_parent = prefix / "share" / "msdev" / "package"
    destination = package_parent / "msdev"
    temporary = package_parent / f".msdev.tmp.{os.getpid()}"
    package_parent.mkdir(parents=True, exist_ok=True)
    shutil.rmtree(temporary, ignore_errors=True)
    shutil.copytree(source, temporary, ignore=shutil.ignore_patterns("__pycache__", "*.pyc"))

    backup = package_parent / ".msdev.old"
    shutil.rmtree(backup, ignore_errors=True)
    if destination.exists():
        destination.rename(backup)
    temporary.rename(destination)
    shutil.rmtree(backup, ignore_errors=True)

    bin_dir = prefix / "bin"
    bin_dir.mkdir(parents=True, exist_ok=True)
    python = Path(sys.executable).resolve()
    helpers = Path(__file__).resolve().parent / "src" / "msdev" / "helpers"
    arch_map = {
        "x86_64": "amd64",
        "amd64": "amd64",
        "aarch64": "arm64",
        "arm64": "arm64",
    }
    daemon_src = helpers / f"msdevd-linux-{arch_map.get(os.uname().machine, '')}"
    if sys.platform != "win32" and daemon_src.is_file():
        shutil.copy2(daemon_src, bin_dir / "msdevd")
        os.chmod(bin_dir / "msdevd", 0o755)
    for command, module in (("msdev", "msdev.cli"),):
        if sys.platform == "win32":
            wrapper = bin_dir / f"{command}.cmd"
            wrapper.write_text(
                "@echo off\r\n"
                f"set \"PYTHONPATH={package_parent};%PYTHONPATH%\"\r\n"
                f"\"{python}\" -m {module} %*\r\n",
                encoding="utf-8",
            )
        else:
            wrapper = bin_dir / command
            wrapper.write_text(
                "#!/usr/bin/env bash\n"
                "set -e\n"
                f"export PYTHONPATH={str(package_parent)!r}"
                '"${PYTHONPATH:+:${PYTHONPATH}}"\n'
                f"exec {str(python)!r} -m {module} \"$@\"\n",
                encoding="utf-8",
            )
            os.chmod(wrapper, 0o755)
    if sys.platform == "win32":
        wrapper = bin_dir / "msdevd.cmd"
        wrapper.write_text(
            "@echo off\r\n"
            f"set \"PYTHONPATH={package_parent};%PYTHONPATH%\"\r\n"
            f"\"{python}\" -m msdev.daemon %*\r\n",
            encoding="utf-8",
        )
    elif not (bin_dir / "msdevd").exists():
        raise RuntimeError(
            f"Go msdevd binary not found: {daemon_src}. "
            "Run bash msdevd/build-static.sh before install-user.py"
        )

    print(f"installed msdev package to {package_parent}")
    print(f"installed commands to {bin_dir}")
    path_sep = ";" if sys.platform == "win32" else ":"
    path_hint = (
        f"set PATH={bin_dir}{path_sep}%PATH%"
        if sys.platform == "win32"
        else f"export PATH={bin_dir!s}:$PATH"
    )
    if str(bin_dir) not in os.environ.get("PATH", "").split(os.pathsep):
        print(f"add this directory to PATH: {path_hint}")


def main() -> None:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument(
        "--prefix",
        type=Path,
        default=Path.home() / ".local",
        help="installation prefix (default: ~/.local)",
    )
    args = parser.parse_args()
    install(args.prefix)


if __name__ == "__main__":
    main()