"""Build a project using PEP 517 hooks.
"""
import argparse
import logging
import os
import shutil
import tempfile

from ._compat import tomllib
from .envbuild import BuildEnvironment
from .wrappers import Pep517HookCaller

log = logging.getLogger(__name__)


def validate_system(system):
    """
    Ensure build system has the requisite fields.
    """
    required = {"requires", "build-backend"}
    if not (required <= set(system)):
        message = "Missing required fields: {missing}".format(
            missing=required - set(system),
        )
        raise ValueError(message)


def load_system(source_dir):
    """
    Load the build system from a source dir (pyproject.toml).
    """
    pyproject = os.path.join(source_dir, "pyproject.toml")
    with open(pyproject, "rb") as f:
        pyproject_data = tomllib.load(f)
    return pyproject_data["build-system"]


def compat_system(source_dir):
    """
    Given a source dir, attempt to get a build system backend
    and requirements from pyproject.toml. Fallback to
    setuptools but only if the file was not found or a build
    system was not indicated.
    """
    try:
        system = load_system(source_dir)
    except (FileNotFoundError, KeyError):
        system = {}
    system.setdefault(
        "build-backend",
        "setuptools.build_meta:__legacy__",
    )
    system.setdefault("requires", ["setuptools", "wheel"])
    return system


def _do_build(hooks, env, dist, dest):
    get_requires_name = "get_requires_for_build_{dist}".format(**locals())
    get_requires = getattr(hooks, get_requires_name)
    reqs = get_requires({})
    log.info("Got build requires: %s", reqs)

    env.pip_install(reqs)
    log.info("Installed dynamic build dependencies")

    with tempfile.TemporaryDirectory() as td:
        log.info("Trying to build %s in %s", dist, td)
        build_name = "build_{dist}".format(**locals())
        build = getattr(hooks, build_name)
        filename = build(td, {})
        source = os.path.join(td, filename)
        shutil.move(source, os.path.join(dest, os.path.basename(filename)))


def build(source_dir, dist, dest=None, system=None):
    system = system or load_system(source_dir)
    dest = os.path.join(source_dir, dest or "dist")
    os.makedirs(dest, exist_ok=True)

    validate_system(system)
    hooks = Pep517HookCaller(
        source_dir, system["build-backend"], system.get("backend-path")
    )

    with BuildEnvironment() as env:
        env.pip_install(system["requires"])
        _do_build(hooks, env, dist, dest)


parser = argparse.ArgumentParser()
parser.add_argument(
    "source_dir",
    help="A directory containing pyproject.toml",
)
parser.add_argument(
    "--binary",
    "-b",
    action="store_true",
    default=False,
)
parser.add_argument(
    "--source",
    "-s",
    action="store_true",
    default=False,
)
parser.add_argument(
    "--out-dir",
    "-o",
    help="Destination in which to save the builds relative to source dir",
)


def main(args):
    log.warning(
        "pep517.build is deprecated. "
        "Consider switching to https://pypi.org/project/build/"
    )

    # determine which dists to build
    dists = list(
        filter(
            None,
            (
                "sdist" if args.source or not args.binary else None,
                "wheel" if args.binary or not args.source else None,
            ),
        )
    )

    for dist in dists:
        build(args.source_dir, dist, args.out_dir)


if __name__ == "__main__":
    main(parser.parse_args())
