import os
import subprocess
import sys
from pathlib import Path
import platform
from tempfile import TemporaryDirectory
from typing import TypeAlias, TYPE_CHECKING, Mapping

from setuptools import setup, Extension, Command
from setuptools.command.build_ext import build_ext

import versioneer

import requirements


def fix_path(path: str | os.PathLike[str]) -> str:
    return os.path.realpath(path).replace(os.sep, "/")


cmdclass: dict[str, type[Command]] = versioneer.get_cmdclass()

if TYPE_CHECKING:
    BuildExt: TypeAlias = build_ext
else:
    BuildExt = cmdclass.get("build_ext", build_ext)


class CMakeBuild(BuildExt):
    def build_extension(self, ext: Extension) -> None:
        import pybind11
        import amulet.pybind11_extensions

        ext_dir = (Path.cwd() / self.get_ext_fullpath("")).parent.resolve() / "rocksdb"
        rocksdb_src_dir = (
            Path.cwd() / "src" / "amulet" / "rocksdb" if self.editable_mode else ext_dir
        )

        platform_args = []
        if sys.platform == "win32":
            platform_args.extend(["-G", "Visual Studio 17 2022"])
            if sys.maxsize > 2**32:
                platform_args.extend(["-A", "x64"])
            else:
                platform_args.extend(["-A", "Win32"])
            platform_args.extend(["-T", "v143"])
        elif sys.platform == "darwin":
            if platform.machine() == "arm64":
                # rocksdb does not support universal builds
                arch = platform.machine()
                platform_args.append(f"-DCMAKE_OSX_ARCHITECTURES={arch}")

        if subprocess.run(["cmake", "--version"]).returncode:
            raise RuntimeError("Could not find cmake")
        with TemporaryDirectory() as tempdir:
            if subprocess.run(
                [
                    "cmake",
                    *platform_args,
                    f"-DPython3_ROOT_DIR={sys.base_prefix}",
                    f"-Dpybind11_DIR={fix_path(pybind11.get_cmake_dir())}",
                    f"-Damulet_pybind11_extensions_DIR={fix_path(amulet.pybind11_extensions.__path__[0])}",
                    f"-Damulet_rocksdb_DIR={fix_path(rocksdb_src_dir)}",
                    f"-DAMULET_ROCKSDB_EXT_DIR={fix_path(ext_dir)}",
                    f"-DCMAKE_INSTALL_PREFIX=install",
                    "-B",
                    tempdir,
                ]
            ).returncode:
                raise RuntimeError("Error configuring amulet-rocksdb")
            if subprocess.run(
                ["cmake", "--build", tempdir, "--config", "Release"]
            ).returncode:
                raise RuntimeError("Error building amulet-rocksdb")
            if subprocess.run(
                ["cmake", "--install", tempdir, "--config", "Release"]
            ).returncode:
                raise RuntimeError("Error installing amulet-rocksdb")


cmdclass["build_ext"] = CMakeBuild  # type: ignore


options: Mapping[str, Mapping[str, str]] = {}

if sys.platform == "darwin":
    arch = platform.machine()
    if arch not in ("arm64", "x86_64"):
        raise RuntimeError(f"Unsupported architecture: {arch}")
    options["bdist_wheel"] = {"plat_name": f"macosx_11_0_{arch}"}


setup(
    version=versioneer.get_version(),
    cmdclass=cmdclass,
    ext_modules=[Extension("rocksdb._rocksdb", [])]
    * (not os.environ.get("AMULET_SKIP_COMPILE", None)),
    install_requires=requirements.get_runtime_dependencies(),
    options=options,
)
