import os
from pathlib import Path

import pytest

import nltk.parse.malt as malt
from nltk.parse.malt import MaltParser


def _minimal_malt_parser(tmp_path, monkeypatch):
    # Place the (dummy) maltparser jar inside a trusted nltk_data root so the
    # JAR-execution sandbox permits it. These tests then exercise the REAL,
    # sandboxed command path (a legitimate in-nltk_data jar), not an escape hatch.
    data_root = tmp_path / "nltk_data"
    jar_dir = data_root / "maltparser"
    jar_dir.mkdir(parents=True)
    malt_jar = jar_dir / "maltparser-1.9.2.jar"
    malt_jar.write_bytes(b"")
    monkeypatch.setattr("nltk.data.path", [str(data_root)])

    model_dir = tmp_path / "model"
    model_dir.mkdir()
    model_file = model_dir / "model.mco"
    model_file.write_text("dummy model\n", encoding="utf-8")

    working_dir = tmp_path / "work"
    working_dir.mkdir()

    parser = MaltParser.__new__(MaltParser)
    parser._trained = True
    parser.model = str(model_file)
    parser.working_dir = str(working_dir)
    parser.malt_jars = [str(malt_jar)]
    parser.additional_java_args = []
    return parser, model_dir


def _write_minimal_parse(cmd):
    output_path = Path(cmd[cmd.index("-o") + 1])
    output_path.write_text(
        "1\thello\t_\tNN\tNN\t_\t0\tnull\t_\t_\n",
        encoding="utf-8",
    )


def test_malt_parse_uses_subprocess_cwd_without_changing_process_cwd(
    monkeypatch, tmp_path
):
    parser, model_dir = _minimal_malt_parser(tmp_path, monkeypatch)
    service_dir = tmp_path / "service"
    service_dir.mkdir()
    monkeypatch.chdir(service_dir)

    def forbidden_chdir(path):
        raise AssertionError(f"os.chdir() should not be called with {path!r}")

    monkeypatch.setattr(malt.os, "chdir", forbidden_chdir)

    captured = {}

    def fake_execute(cmd, verbose=False, cwd=None):
        captured["cwd"] = cwd
        captured["process_cwd"] = os.getcwd()
        captured["input_file"] = Path(cmd[cmd.index("-i") + 1])
        captured["output_file"] = Path(cmd[cmd.index("-o") + 1])
        _write_minimal_parse(cmd)
        return 0

    parser._execute = fake_execute

    graphs = list(parser.parse_tagged_sents([[("hello", "NN")]]))

    assert len(graphs) == 1
    assert captured["cwd"] == str(model_dir)
    assert captured["process_cwd"] == str(service_dir)
    assert os.getcwd() == str(service_dir)
    assert not captured["input_file"].exists()
    assert not captured["output_file"].exists()


def test_malt_parse_cleans_temp_files_and_preserves_cwd_on_execute_exception(
    monkeypatch, tmp_path
):
    parser, model_dir = _minimal_malt_parser(tmp_path, monkeypatch)
    service_dir = tmp_path / "service"
    service_dir.mkdir()
    monkeypatch.chdir(service_dir)

    captured = {}

    def fake_execute(cmd, verbose=False, cwd=None):
        captured["cwd"] = cwd
        captured["process_cwd"] = os.getcwd()
        captured["input_file"] = Path(cmd[cmd.index("-i") + 1])
        captured["output_file"] = Path(cmd[cmd.index("-o") + 1])
        assert captured["input_file"].exists()
        assert captured["output_file"].exists()
        raise RuntimeError("forced parser failure")

    parser._execute = fake_execute

    with pytest.raises(RuntimeError, match="forced parser failure"):
        list(parser.parse_tagged_sents([[("hello", "NN")]]))

    assert captured["cwd"] == str(model_dir)
    assert captured["process_cwd"] == str(service_dir)
    assert os.getcwd() == str(service_dir)
    assert not captured["input_file"].exists()
    assert not captured["output_file"].exists()
