"""Integration tests for the CLI entry point."""
import os
import pathlib
import stat
import subprocess
import sys
import textwrap


def _write_script(path: pathlib.Path, content: str) -> None:
    path.write_text(content)
    path.chmod(path.stat().st_mode | stat.S_IEXEC)


def test_cli_reduces_file(tmp_path):
    input_file = tmp_path / "test.txt"
    input_file.write_text("keep\nremove1\nremove2\n")

    script = tmp_path / "check.sh"
    _write_script(
        script,
        textwrap.dedent("""\
            #!/bin/sh
            grep -q 'keep' test.txt
        """),
    )

    result = subprocess.run(
        [
            sys.executable, "-m", "delta_reduce",
            "--test", str(script),
            "--input", str(input_file),
            "-n", "1",
        ],
        capture_output=True,
        text=True,
    )
    assert result.returncode == 0, result.stderr
    assert input_file.read_text() == "keep\n"


def test_cli_creates_orig_backup(tmp_path):
    input_file = tmp_path / "test.txt"
    original_content = "keep\nremove\n"
    input_file.write_text(original_content)

    script = tmp_path / "check.sh"
    _write_script(
        script,
        textwrap.dedent("""\
            #!/bin/sh
            grep -q 'keep' test.txt
        """),
    )

    subprocess.run(
        [
            sys.executable, "-m", "delta_reduce",
            "--test", str(script),
            "--input", str(input_file),
            "-n", "1",
        ],
        capture_output=True,
    )

    orig = tmp_path / "test.txt.orig"
    assert orig.exists()
    assert orig.read_text() == original_content


def test_cli_does_not_overwrite_existing_orig(tmp_path):
    input_file = tmp_path / "test.txt"
    input_file.write_text("keep\nremove\n")

    orig = tmp_path / "test.txt.orig"
    orig.write_text("the very original\n")

    script = tmp_path / "check.sh"
    _write_script(
        script,
        textwrap.dedent("""\
            #!/bin/sh
            grep -q 'keep' test.txt
        """),
    )

    subprocess.run(
        [
            sys.executable, "-m", "delta_reduce",
            "--test", str(script),
            "--input", str(input_file),
            "-n", "1",
        ],
        capture_output=True,
    )

    assert orig.read_text() == "the very original\n"


def test_subprocess_killed_when_cancelled(tmp_path):
    """test_fn must kill the subprocess and return False when is_cancelled() returns True."""
    import threading
    import time
    from delta_reduce.__main__ import _make_test_fn

    script = tmp_path / "slow.sh"
    _write_script(script, "#!/bin/sh\nsleep 5\n")

    test_fn = _make_test_fn(script, "input.txt")
    cancelled = False
    is_cancelled = lambda: cancelled
    candidate = ["line\n"]
    result_holder: list[bool] = []

    def run() -> None:
        result_holder.append(test_fn(candidate, is_cancelled))

    t = threading.Thread(target=run)
    t0 = time.monotonic()
    t.start()
    time.sleep(0.1)
    cancelled = True
    t.join(timeout=2.0)
    elapsed = time.monotonic() - t0

    assert not t.is_alive(), "test_fn did not return after is_cancelled() started returning True"
    assert elapsed < 0.5, f"Expected fast cancellation, took {elapsed:.2f}s"
    assert result_holder == [False]


def test_cli_test_script_runs_with_input_filename_in_cwd(tmp_path):
    """The test script must see the candidate as the original filename in its cwd."""
    input_file = tmp_path / "myfile.txt"
    input_file.write_text("keep\nremove\n")

    # Script deliberately references the filename, not a path
    script = tmp_path / "check.sh"
    _write_script(
        script,
        textwrap.dedent("""\
            #!/bin/sh
            grep -q 'keep' myfile.txt
        """),
    )

    result = subprocess.run(
        [
            sys.executable, "-m", "delta_reduce",
            "--test", str(script),
            "--input", str(input_file),
            "-n", "1",
        ],
        capture_output=True,
        text=True,
    )
    assert result.returncode == 0, result.stderr
    assert input_file.read_text() == "keep\n"
