# SPDX-FileCopyrightText: Peter Pentchev <roam@ringlet.net>
# SPDX-License-Identifier: BSD-2-Clause
"""Parse command-line arguments, run a command in a temporary directory."""

from __future__ import annotations

import os
import pathlib
import shutil
import subprocess  # noqa: S404
import sys
import tempfile
import typing

import click

from . import defs
from . import util


if typing.TYPE_CHECKING:
    from typing import Final


def arg_features(_ctx: click.Context, _self: click.Parameter, value: bool) -> bool:  # noqa: FBT001
    """Display program features information and exit."""
    if not value:
        return value

    print(  # noqa: T201
        "Features: " + " ".join(f"{name}={value}" for name, value in defs.FEATURES.items()),
    )
    sys.exit(0)


def run(cfg: defs.Config) -> None:
    """Create a temporary directory, copy the test file there, run the test."""
    testf: Final = cfg.srcdir / "regex_3" / "test_regex.py"
    if not testf.is_file():
        sys.exit(f"Not a regular file: {testf}")

    with tempfile.TemporaryDirectory(prefix="regex-temp-test.") as tempd_obj:
        tempd: Final = pathlib.Path(tempd_obj)
        cfg.log.debug("Using %(tempd)s as a temporary directory", {"tempd": tempd})
        destf: Final = tempd / testf.name
        cfg.log.debug("Copying %(src)s to %(dst)s", {"src": testf, "dst": destf})
        shutil.copy2(testf, destf)

        pyenv: Final = dict(os.environ)

        def add_pypath(path: pathlib.Path) -> None:
            """Add the specified path to PYTHONPATH or set it if it isn't set at all."""
            current: Final = pyenv.get("PYTHONPATH")
            if current is None:
                pyenv["PYTHONPATH"] = str(path)
            else:
                pyenv["PYTHONPATH"] = f"{path}:{current}"

        if cfg.pybuild is not None:
            pypath: Final = (
                cfg.pybuild / f"cpython3_{sys.version_info[0]}.{sys.version_info[1]}" / "build"
            )
            if not pypath.is_dir():
                sys.exit(f"Not a directory: {pypath}")
            add_pypath(pypath)

        if cfg.pypath is not None:
            add_pypath(cfg.pypath)

        subprocess.check_call(  # noqa: S603
            [sys.executable, "-B", "-u", "--", destf],
            cwd=tempd,
            env=pyenv,
        )


@click.command(name="temptest")
@click.option(
    "--features",
    is_flag=True,
    is_eager=True,
    callback=arg_features,
    help="display program features information and exit",
)
@click.option(
    "--pybuild",
    type=click.Path(
        exists=True,
        file_okay=False,
        dir_okay=True,
        path_type=pathlib.Path,
        resolve_path=True,
    ),
    help="the .pybuild directory to look for the built Python module in",
)
@click.option(
    "--pypath",
    type=click.Path(
        exists=True,
        file_okay=False,
        dir_okay=True,
        path_type=pathlib.Path,
        resolve_path=True,
    ),
    help="the built Python module parent directory to add to PYTHONPATH",
)
@click.option(
    "--quiet",
    "-q",
    is_flag=True,
    help="quiet operation; only display warning and error messages",
)
@click.option(
    "--srcdir",
    type=click.Path(
        exists=True,
        file_okay=False,
        dir_okay=True,
        path_type=pathlib.Path,
        resolve_path=True,
    ),
    required=True,
    help="the directory to look for the regex module source code",
)
@click.option("--verbose", "-v", is_flag=True, help="verbose operation; display diagnostic output")
def main(  # noqa: PLR0913  # yep, we like command-line arguments
    *,
    features: bool,
    pybuild: pathlib.Path | None,
    pypath: pathlib.Path | None,
    quiet: bool,
    srcdir: pathlib.Path,
    verbose: bool,
) -> None:
    """Parse command-line arguments, copy test-regex to a temporary directory, run it."""
    if features:
        sys.exit("Internal error: how did we get to main() with features=True?")

    cfg: Final = defs.Config(
        log=util.build_logger(quiet=quiet, verbose=verbose),
        pybuild=pybuild,
        pypath=pypath,
        srcdir=srcdir,
        verbose=verbose,
    )
    run(cfg)


if __name__ == "__main__":
    main()
