"""End-to-end test: build a self-contained CFFI extension with meson-python.

The test provisions a fresh nested venv under ``tmp_path`` using the
stdlib :mod:`venv` module, installs ``cffi`` (from the current source
tree) and ``meson-python`` into it, installs one of the small example
projects that live under ``testing/cffi1/cffi_gen_src_examples/``, and then
imports the built extension to confirm it works.

"""

import os
import re
import shutil
import subprocess
import sys
from pathlib import Path

import pytest

import cffi

pytestmark = [
    pytest.mark.thread_unsafe(reason="spawns subprocesses, slow"),
]

try:
    import mesonpy
except ImportError:
    pytest.skip("Test requires meson-python", allow_module_level=True)


HERE = Path(__file__).resolve().parent
EXAMPLE_PROJECT = HERE / "cffi_gen_src_examples" / "exec_python_example"
EXAMPLE_PROJECT2 = HERE / "cffi_gen_src_examples" / "read_sources_example"
CFFI_DIR = HERE.parent.parent


def _venv_python(venv_dir):
    if sys.platform == "win32":
        return venv_dir / "Scripts" / "python.exe"
    return venv_dir / "bin" / "python"


@pytest.mark.parametrize("project", [EXAMPLE_PROJECT, EXAMPLE_PROJECT2])
def test_meson_python_build(tmp_path, project):
    venv_dir = tmp_path / "venv"
    subprocess.check_call([sys.executable, "-m", "venv", str(venv_dir)])
    venv_python = _venv_python(venv_dir)
    assert venv_python.exists(), venv_python

    # Upgrade pip so --no-build-isolation behaves consistently with recent
    # resolver behaviour on older base images.
    subprocess.check_call([
        str(venv_python), "-m", "pip", "install", "--upgrade", "pip",
    ])

    # Install build-time deps into the nested venv.
    subprocess.check_call([
        str(venv_python), "-m", "pip", "install", "meson-python", CFFI_DIR
    ])

    # Copy the example project so nothing is written back into the
    # source tree
    project_dir = tmp_path / "project"
    shutil.copytree(project, project_dir)

    # The example meson.build files locate the codegen tool with
    # find_program('cffi-gen-src'), which searches PATH. pip only puts
    # an environment's scripts directory on PATH for isolated builds,
    # so with --no-build-isolation the nested venv's script must be
    # made findable by hand.
    env = os.environ.copy()
    env["PATH"] = str(venv_python.parent) + os.pathsep + env.get("PATH", "")

    # --no-build-isolation to ensure the test runs against the CFFI build we want to test
    proc = subprocess.run([
        str(venv_python), "-m", "pip", "install", "-v",
        "--no-build-isolation", str(project_dir),
    ], env=env, capture_output=True, text=True)
    assert proc.returncode == 0, proc.stdout + proc.stderr

    # Confirm the built extension imports and behaves as expected.
    subprocess.check_call([
        str(venv_python), "-c",
        "from squared import squared; "
        "assert squared(7) == 49; "
        "assert squared(-3) == 9",
    ])
