from __future__ import annotations

import os
import platform
import shutil
import struct
import sys
from pathlib import Path

from setuptools import setup
from setuptools.command.build_py import build_py as _build_py

try:
    from wheel.bdist_wheel import bdist_wheel as _bdist_wheel
except ImportError:
    _bdist_wheel = None


PACKAGE_ROOT = Path(__file__).resolve().parent
REPO_ROOT = PACKAGE_ROOT.parent.parent
PACKAGE_NAME = "omnidraw_launcher"
ENV_BUILD_BINARY = "OMNIDRAW_PACKAGE_BINARY"


def _default_binary_candidates() -> list[Path]:
    names = ["omnidraw.exe", "omnidraw"]
    parents = [
        REPO_ROOT / "zzbuild-live" / "release",
        REPO_ROOT / "zzbuild-live2" / "release",
        REPO_ROOT / "zzbuild" / "release",
        REPO_ROOT / "target" / "release",
    ]
    return [parent / name for parent in parents for name in names]


def _resolve_binary_path() -> Path:
    override = os.environ.get(ENV_BUILD_BINARY)
    candidates = [Path(override)] if override else []
    candidates.extend(_default_binary_candidates())
    for candidate in candidates:
        if candidate.exists() and candidate.is_file():
            return candidate.resolve()
    checked = "\n".join(f"- {path}" for path in candidates) or "- <none>"
    raise RuntimeError(
        "Cannot package OmniDraw because no Rust binary was found.\n"
        f"Set {ENV_BUILD_BINARY} to a built omnidraw binary, or build one into one of:\n{checked}"
    )


def _plat_name() -> str:
    """Return a PEP 425 platform tag matching the bundled Rust binary."""
    override = os.environ.get("OMNIDRAW_PLAT_NAME")
    if override:
        return override
    if sys.platform == "win32":
        bits = struct.calcsize("P") * 8
        return "win_amd64" if bits == 64 else "win32"
    if sys.platform == "darwin":
        machine = platform.machine()
        if machine == "arm64":
            return "macosx_11_0_arm64"
        return "macosx_10_9_x86_64"
    machine = platform.machine()
    if machine == "x86_64":
        return "manylinux_2_17_x86_64"
    if machine == "aarch64":
        return "manylinux_2_17_aarch64"
    return f"linux_{machine}"


class build_py(_build_py):
    def run(self) -> None:
        super().run()
        binary_path = _resolve_binary_path()
        binary_name = "omnidraw.exe" if binary_path.suffix.lower() == ".exe" else "omnidraw"
        dest_dir = Path(self.build_lib) / PACKAGE_NAME / "bin"
        dest_dir.mkdir(parents=True, exist_ok=True)
        shutil.copy2(binary_path, dest_dir / binary_name)


cmdclass: dict = {"build_py": build_py}

if _bdist_wheel is not None:
    class bdist_wheel(_bdist_wheel):  # type: ignore[misc]
        def finalize_options(self) -> None:
            super().finalize_options()
            self.root_is_pure = False
            self.plat_name_supplied = True
            self.plat_name = _plat_name()

        def get_tag(self) -> tuple[str, str, str]:
            return "py3", "none", _plat_name().replace("-", "_").replace(".", "_")

    cmdclass["bdist_wheel"] = bdist_wheel

setup(
    cmdclass=cmdclass,
    package_data={PACKAGE_NAME: ["bin/*"]},
)
