import os

from setuptools import find_packages, setup
from setuptools.config import read_configuration


class Package:
    def __init__(self, config):
        metadata = config["metadata"]
        options = config["options"]

        self.options = options
        self.name = metadata["name"]
        self.version = metadata["version"]

    def tests_require(self):
        return self.options["tests_require"] + self.options["install_requires"]

    def read_egg_version(self):
        pkg_info_file = None
        # PKG-INFO can be in different places depending on whether we are a
        # source distribution or a checked out copy etc.
        for location in [
            "PKG-INFO",
            "src/" + self.name + ".egg-info/PKG-INFO",
            self.name + ".egg-info/PKG-INFO",
        ]:
            if os.path.isfile(location):
                pkg_info_file = location

        if not pkg_info_file:
            return None

        with open(pkg_info_file) as fh:
            for line in fh:
                if line.startswith("Version"):
                    return line.strip().split("Version: ")[-1]

    def get_version(self, build_var="BUILD"):
        """Gets a version reading from the specified environment variable

        This expects the variable to contain something like:

         * refs/heads/<branch_name> - This will be ignored
         * refs/tags/v<version> - This will be used if it matches our major
                                  minor number
         * v<version> - This will be used if it matches our major minor number

        If this is not present then we will read from the .egg-info/ data if
        possible.

        Finally a fallback development version is provided.

        :param build_var: The enviroment to
        :return: A version string
        """
        # If we have a build argument we should honour it if we can
        build = os.environ.get(build_var)
        if build:
            if build.startswith("refs/heads/"):
                # We are being built via CI from a branch: we'll return a
                # dummy value marking this as an 'alpha' release
                return self.version + ".a0"

            if build.startswith("refs/tags/"):
                # We are being built via CI from a tag: strip the refs stuff
                build = build.replace("refs/tags/", "")

            start = "v" + self.version + "."
            if not build.startswith(start):
                raise ValueError(f'Expected build to be "{start}*", got "{build}"')

            return self.version + "." + build[len(start) :]

        # If not, we should try and read it from the .egg-info/ data

        # We need to do this for source distributions, as setup.py is re-run
        # when installed this way, and we would always get 'dev0' as the
        # version wheels and binary installs don't work this way and read
        # from PKG-INFO for them selves
        egg_version = self.read_egg_version()
        if egg_version:
            return egg_version

        # Otherwise create a 'dev' build which will be counted by pip as
        # 'later' than the major version no matter what
        return self.version + ".dev0"


package = Package(read_configuration("setup.cfg"))

setup(
    # Metadata
    # https://docs.python.org/3/distutils/setupscript.html#additional-meta-data
    version=package.get_version(),
    # Contents and dependencies
    packages=find_packages(where="src"),
    package_dir={"": "src"},
    # Read the MANIFEST.in
    include_package_data=True,
    # Add support for pip install .[tests]
    extras_require={"tests": package.tests_require()},
    tests_require=package.tests_require(),
)
