#!/usr/bin/env python3
# Copyright (C) 2024 Efabless Corporation
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
import os
import re
import shlex
import shutil
from pathlib import Path
from setuptools import setup, Extension

import pybind11
from pybind11.setup_helpers import build_ext

__yosys_root__ = Path(__file__).parent

yosys_version_rx = re.compile(r"YOSYS_VER\s*:=\s*([\w\-\+\.]+)")

with open(__yosys_root__ / "Makefile", encoding="utf8") as f:
    # Extract and convert + to patch version
    version = yosys_version_rx.search(f.read())[1].replace("+", ".")


class libyosys_so_ext(Extension):
    def __init__(
        self,
    ) -> None:
        super().__init__(
            "libyosys.so",
            [],
        )

        # when iterating locally, you probably want to set this variable
        # to avoid mass rebuilds bec of pybind11's include path changing
        pybind_include = os.getenv("_FORCE_PYBIND_INCLUDE", pybind11.get_include())

        self.args = [
            f"PYBIND11_INCLUDE={pybind_include}",
            "ENABLE_PYOSYS=1",
            # Would need to be installed separately by the user
            "ENABLE_TCL=0",
            "ENABLE_READLINE=0",
            "ENABLE_EDITLINE=0",
            "PYOSYS_USE_UV=0", # + install requires takes its role when building wheels
            # Always compile and include ABC in wheel
            "ABCEXTERNAL=",
            # Show compile commands
            "PRETTY=0",
        ]

    def custom_build(self, bext: build_ext):
        make_flags_split = shlex.split(os.getenv("makeFlags", ""))
        # abc linking takes a lot of memory, best get it out of the way first
        bext.spawn(
            [
                "make",
                f"-j{os.cpu_count() or 1}",
                "yosys-abc",
                *make_flags_split,
                *self.args,
            ]
        )
        # build libyosys and share with abc out of the way
        bext.spawn(
            [
                "make",
                f"-j{os.cpu_count() or 1}",
                self.name,
                "share",
                *make_flags_split,
                *self.args,
            ]
        )
        ext_fullpath = Path(bext.get_ext_fullpath(self.name))
        build_path = ext_fullpath.parents[1]
        pyosys_path = build_path / "pyosys"
        os.makedirs(pyosys_path, exist_ok=True)

        # libyosys.so
        target = pyosys_path / self.name
        shutil.copy(self.name, target)
        bext.spawn(["strip", "-S", str(target)])

        # yosys-abc
        yosys_abc_target = pyosys_path / "yosys-abc"
        shutil.copy("yosys-abc", yosys_abc_target)
        bext.spawn(["strip", "-S", str(yosys_abc_target)])

        # share directory
        share_target = pyosys_path / "share"
        try:
            shutil.rmtree(share_target)
        except FileNotFoundError:
            pass

        shutil.copytree("share", share_target)


class custom_build_ext(build_ext):
    def build_extension(self, ext) -> None:
        if not hasattr(ext, "custom_build"):
            return super().build_extension(ext)
        return ext.custom_build(self)


with open(__yosys_root__ / "README.md", encoding="utf8") as f:
    long_description = f.read()

setup(
    name="pyosys",
    packages=["pyosys"],
    version=version,
    description="Python access to libyosys",
    long_description=long_description,
    long_description_content_type="text/markdown",
    license="MIT",
    classifiers=[
        "Programming Language :: Python :: 3",
        "Intended Audience :: Developers",
        "Operating System :: POSIX :: Linux",
        "Operating System :: MacOS :: MacOS X",
    ],
    python_requires=">=3.8",
    ext_modules=[libyosys_so_ext()],
    cmdclass={
        "build_ext": custom_build_ext,
    },
)
