"""Tests for autobuilder_hook_helpers.fix_agent."""

import subprocess
import sys
from pathlib import Path
from unittest.mock import MagicMock, patch

import pytest

sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "hook-helpers"))

from autobuilder_hook_helpers.fix_agent import (
    _build_cmd,
    build_ci_fix_prompt,
    build_deploy_fix_prompt,
    run_fix_agent,
)


class TestBuildCmd:
    def test_cursor_default(self):
        cmd = _build_cmd("cursor", None, "fix this")
        assert cmd[0] == "cursor"
        assert "--yolo" in cmd
        assert cmd[-1] == "fix this"

    def test_cursor_with_model(self):
        cmd = _build_cmd("cursor", "claude-4.7-opus", "fix this")
        assert "--model" in cmd
        idx = cmd.index("--model")
        assert cmd[idx + 1] == "claude-4.7-opus"

    def test_codex(self):
        cmd = _build_cmd("codex", None, "fix this")
        assert cmd[0] == "codex"
        assert "--dangerously-bypass-approvals-and-sandbox" in cmd
        assert cmd[-1] == "fix this"

    def test_codex_with_model(self):
        cmd = _build_cmd("codex", "o3", "fix this")
        assert "--model" in cmd
        idx = cmd.index("--model")
        assert cmd[idx + 1] == "o3"


class TestBuildCiFixPrompt:
    def test_contains_logs(self):
        prompt = build_ci_fix_prompt("TypeError: cannot read property")
        assert "TypeError: cannot read property" in prompt
        assert "CI/CD pipeline failed" in prompt
        assert "Do NOT run git push" in prompt


class TestBuildDeployFixPrompt:
    def test_basic(self):
        prompt = build_deploy_fix_prompt(
            "npm ERR! build failed",
            project_id="myapp",
            port=3080,
        )
        assert "npm ERR! build failed" in prompt
        assert "deployment" in prompt.lower()

    def test_with_server_access(self):
        prompt = build_deploy_fix_prompt(
            "build error",
            project_id="myapp",
            port=3080,
            server_host="10.0.0.1",
            server_user="deploy",
            deploy_domain="example.com",
        )
        assert "10.0.0.1" in prompt
        assert "deploy@10.0.0.1" in prompt
        assert "https://myapp.example.com" in prompt

    def test_no_server_access(self):
        prompt = build_deploy_fix_prompt(
            "build error",
            project_id="myapp",
            port=3080,
        )
        assert "SSH" not in prompt

    def test_custom_ssh_key(self):
        prompt = build_deploy_fix_prompt(
            "build error",
            project_id="myapp",
            port=3080,
            server_host="10.0.0.1",
            server_user="deploy",
            ssh_key="~/.ssh/custom_key",
        )
        assert "custom_key" in prompt
        assert "id_ed25519" not in prompt

    def test_custom_app_dir(self):
        prompt = build_deploy_fix_prompt(
            "build error",
            project_id="myapp",
            port=3080,
            server_host="10.0.0.1",
            server_user="deploy",
            app_dir="/opt/apps/myapp",
        )
        assert "/opt/apps/myapp" in prompt
        assert "~/apps/" not in prompt

    def test_default_ssh_key_and_app_dir(self):
        prompt = build_deploy_fix_prompt(
            "build error",
            project_id="myapp",
            port=3080,
            server_host="10.0.0.1",
            server_user="deploy",
        )
        assert "id_ed25519" in prompt
        assert "~/apps/myapp" in prompt


class TestRunFixAgent:
    def test_success(self, tmp_path):
        mock_proc = MagicMock()
        mock_proc.pid = 9999
        mock_proc.stdout = iter(["fixing...\n", "done\n"])
        mock_proc.wait.return_value = None
        mock_proc.returncode = 0
        mock_proc.poll.return_value = 0

        with patch("subprocess.Popen", return_value=mock_proc):
            rc = run_fix_agent(tmp_path, "fix the bug")
        assert rc == 0

    def test_failure(self, tmp_path):
        mock_proc = MagicMock()
        mock_proc.pid = 9999
        mock_proc.stdout = iter(["error\n"])
        mock_proc.wait.return_value = None
        mock_proc.returncode = 1
        mock_proc.poll.return_value = 1

        with patch("subprocess.Popen", return_value=mock_proc):
            rc = run_fix_agent(tmp_path, "fix the bug")
        assert rc == 1

    def test_binary_not_found(self, tmp_path):
        with patch("subprocess.Popen", side_effect=FileNotFoundError("cursor")):
            rc = run_fix_agent(tmp_path, "fix the bug")
        assert rc == 127

    def test_codex_executor(self, tmp_path):
        mock_proc = MagicMock()
        mock_proc.pid = 9999
        mock_proc.stdout = iter([])
        mock_proc.wait.return_value = None
        mock_proc.returncode = 0
        mock_proc.poll.return_value = 0

        with patch("subprocess.Popen", return_value=mock_proc) as mock_popen:
            run_fix_agent(tmp_path, "fix", executor="codex")
        cmd = mock_popen.call_args[0][0]
        assert cmd[0] == "codex"
