import json
import subprocess

import pytest

from scripts import execute


def test_invoke_codex_uses_utf8_for_unicode_prompt(tmp_path, monkeypatch):
    phase_dir = tmp_path / "phases" / "unicode-phase"
    phase_dir.mkdir(parents=True)
    (phase_dir / "index.json").write_text(
        json.dumps(
            {
                "project": "FESA Structural Solver",
                "phase": "unicode-phase",
                "steps": [{"step": 0, "name": "unicode", "status": "pending"}],
            }
        ),
        encoding="utf-8",
    )
    (phase_dir / "step0.md").write_text("Euler–Bernoulli 보", encoding="utf-8")

    invocation = {}

    def capture_run(command, **kwargs):
        invocation["command"] = command
        invocation["kwargs"] = kwargs
        return subprocess.CompletedProcess(command, 0, stdout="", stderr="")

    monkeypatch.setattr(execute, "ROOT", tmp_path)
    monkeypatch.setattr(execute.subprocess, "run", capture_run)

    executor = execute.StepExecutor("unicode-phase")
    executor._invoke_codex({"step": 0, "name": "unicode"}, "승인된 설계 – ")

    assert "Euler–Bernoulli 보" in invocation["kwargs"]["input"]
    assert invocation["kwargs"]["encoding"] == "utf-8"
    sandbox_index = invocation["command"].index("--sandbox")
    assert invocation["command"][sandbox_index + 1] == "workspace-write"


def test_invoke_codex_accepts_explicit_danger_full_access_override(
    tmp_path, monkeypatch
):
    phase_dir = tmp_path / "phases" / "sandbox-phase"
    phase_dir.mkdir(parents=True)
    (phase_dir / "index.json").write_text(
        json.dumps(
            {
                "project": "FESA Structural Solver",
                "phase": "sandbox-phase",
                "steps": [{"step": 0, "name": "sandbox", "status": "pending"}],
            }
        ),
        encoding="utf-8",
    )
    (phase_dir / "step0.md").write_text("sandbox override", encoding="utf-8")

    invocation = {}

    def capture_run(command, **kwargs):
        invocation["command"] = command
        return subprocess.CompletedProcess(command, 0, stdout="", stderr="")

    monkeypatch.setattr(execute, "ROOT", tmp_path)
    monkeypatch.setattr(execute.subprocess, "run", capture_run)
    monkeypatch.setenv("FESA_HARNESS_CODEX_SANDBOX", "danger-full-access")

    executor = execute.StepExecutor("sandbox-phase")
    executor._invoke_codex({"step": 0, "name": "sandbox"}, "")

    sandbox_index = invocation["command"].index("--sandbox")
    assert invocation["command"][sandbox_index + 1] == "danger-full-access"


def test_invoke_codex_rejects_unknown_sandbox_override(tmp_path, monkeypatch):
    phase_dir = tmp_path / "phases" / "sandbox-phase"
    phase_dir.mkdir(parents=True)
    (phase_dir / "index.json").write_text(
        json.dumps(
            {
                "project": "FESA Structural Solver",
                "phase": "sandbox-phase",
                "steps": [{"step": 0, "name": "sandbox", "status": "pending"}],
            }
        ),
        encoding="utf-8",
    )
    (phase_dir / "step0.md").write_text("sandbox override", encoding="utf-8")

    monkeypatch.setattr(execute, "ROOT", tmp_path)
    monkeypatch.setenv("FESA_HARNESS_CODEX_SANDBOX", "read-only")

    executor = execute.StepExecutor("sandbox-phase")
    with pytest.raises(execute.CodexEnvironmentError, match="FESA_HARNESS_CODEX_SANDBOX"):
        executor._invoke_codex({"step": 0, "name": "sandbox"}, "")


def test_codex_environment_failure_detects_missing_sandbox_helper_on_zero_exit():
    output = {
        "exitCode": 0,
        "stdout": "",
        "stderr": (
            "windows sandbox: orchestrator_helper_launch_failed: "
            "helper=codex-windows-sandbox-setup.exe, error=program not found"
        ),
    }

    assert execute.StepExecutor._codex_environment_failure(output) == (
        "Codex Windows sandbox helper를 실행할 수 없습니다."
    )


def test_run_git_decodes_output_as_utf8(tmp_path, monkeypatch):
    invocation = {}

    def capture_run(command, **kwargs):
        invocation["command"] = command
        invocation["kwargs"] = kwargs
        return subprocess.CompletedProcess(command, 0, stdout="", stderr="")

    monkeypatch.setattr(execute.subprocess, "run", capture_run)
    executor = object.__new__(execute.StepExecutor)
    executor._root = str(tmp_path)

    executor._run_git("status", "--short")

    assert invocation["kwargs"]["encoding"] == "utf-8"


def test_feature_commit_message_is_windows_console_safe():
    message = execute.StepExecutor.FEAT_MSG.format(
        phase="linear-static-3d-euler-beam", num=0, name="requirements-baseline"
    )

    message.encode("cp949")


def test_configure_utf8_stdio_reconfigures_both_streams(monkeypatch):
    class ReconfigurableStream:
        def __init__(self):
            self.encodings = []

        def reconfigure(self, *, encoding):
            self.encodings.append(encoding)

    stdout = ReconfigurableStream()
    stderr = ReconfigurableStream()
    monkeypatch.setattr(execute.sys, "stdout", stdout)
    monkeypatch.setattr(execute.sys, "stderr", stderr)

    execute._configure_utf8_stdio()

    assert stdout.encodings == ["utf-8"]
    assert stderr.encodings == ["utf-8"]
