"""Tests for orchestrator methods on AppXenClient."""

from unittest.mock import MagicMock, patch

import httpx
import pytest

from appxen_cli.client import AppXenClient


class TestOrchestratorMethods:
    """Orchestrator methods on AppXenClient use /orchestrator prefix and API key auth."""

    def _make_client(self) -> AppXenClient:
        return AppXenClient(api_key="axgw_test", endpoint="http://localhost:8000")

    def _mock_response(self, json_data, status_code=200):
        mock_resp = MagicMock(spec=httpx.Response)
        mock_resp.status_code = status_code
        mock_resp.json.return_value = json_data
        mock_resp.raise_for_status = MagicMock()
        return mock_resp

    def test_auth_header_is_bearer(self):
        """Orchestrator methods use Bearer auth (gateway API key), not X-Tenant-Id."""
        client = self._make_client()
        assert client._client.headers["authorization"] == "Bearer axgw_test"
        assert "x-tenant-id" not in client._client.headers
        client.close()

    @patch("httpx.Client.request")
    def test_orchestrator_health(self, mock_request):
        """Health endpoint uses /orchestrator/health path."""
        mock_request.return_value = self._mock_response(
            {"status": "ok", "service": "agent-orchestrator"}
        )
        with self._make_client() as client:
            result = client.orchestrator_health()
            assert result["status"] == "ok"

        call_args = mock_request.call_args
        assert call_args.args[1] == "/orchestrator/health"

    @patch("httpx.Client.request")
    def test_compile_workflow(self, mock_request):
        """Compile sends markdown and returns plan."""
        mock_request.return_value = self._mock_response(
            {"plan": {"name": "Test"}, "notes": [], "usage": {}}
        )
        with self._make_client() as client:
            result = client.compile_workflow("# Test\n")
            assert result["plan"]["name"] == "Test"

        call_args = mock_request.call_args
        assert call_args.args[1] == "/orchestrator/workflows/compile"
        json_body = call_args.kwargs.get("json", {})
        assert json_body["markdown"] == "# Test\n"

    @patch("httpx.Client.request")
    def test_create_workflow(self, mock_request):
        """Create sends name + markdown."""
        mock_request.return_value = self._mock_response(
            {"workflow_id": "wf_123", "plan": {}, "notes": []}
        )
        with self._make_client() as client:
            result = client.create_workflow("my-wf", "# Test\n")
            assert result["workflow_id"] == "wf_123"

        call_args = mock_request.call_args
        assert call_args.args[1] == "/orchestrator/workflows"
        json_body = call_args.kwargs.get("json", {})
        assert json_body["name"] == "my-wf"
        assert json_body["markdown"] == "# Test\n"

    @patch("httpx.Client.request")
    def test_list_workflows(self, mock_request):
        """List returns workflows array."""
        mock_request.return_value = self._mock_response(
            {"workflows": [{"workflow_id": "wf_1", "name": "Test"}]}
        )
        with self._make_client() as client:
            result = client.list_workflows()
            assert len(result["workflows"]) == 1

        call_args = mock_request.call_args
        assert call_args.args[1] == "/orchestrator/workflows"

    @patch("httpx.Client.request")
    def test_get_workflow(self, mock_request):
        """Get returns workflow details."""
        mock_request.return_value = self._mock_response(
            {"workflow_id": "wf_1", "name": "Test", "plan": {}}
        )
        with self._make_client() as client:
            result = client.get_workflow("wf_1")
            assert result["workflow_id"] == "wf_1"

        call_args = mock_request.call_args
        assert call_args.args[1] == "/orchestrator/workflows/wf_1"

    @patch("httpx.Client.request")
    def test_update_workflow(self, mock_request):
        """Update sends markdown to PUT endpoint."""
        mock_request.return_value = self._mock_response(
            {"workflow_id": "wf_1", "plan": {}, "notes": []}
        )
        with self._make_client() as client:
            result = client.update_workflow("wf_1", "# Updated\n")
            assert result["workflow_id"] == "wf_1"

        call_args = mock_request.call_args
        assert call_args.args[0] == "PUT"
        assert call_args.args[1] == "/orchestrator/workflows/wf_1"
        json_body = call_args.kwargs.get("json", {})
        assert json_body["markdown"] == "# Updated\n"

    @patch("httpx.Client.request")
    def test_delete_workflow(self, mock_request):
        """Delete calls DELETE endpoint."""
        mock_resp = MagicMock(spec=httpx.Response)
        mock_resp.status_code = 204
        mock_resp.raise_for_status = MagicMock()
        mock_request.return_value = mock_resp

        with self._make_client() as client:
            client.delete_workflow("wf_1")

        call_args = mock_request.call_args
        assert call_args.args[0] == "DELETE"
        assert call_args.args[1] == "/orchestrator/workflows/wf_1"

    @patch("httpx.Client.request")
    def test_run_workflow(self, mock_request):
        """Run sends inputs and returns execution_id."""
        mock_request.return_value = self._mock_response(
            {"execution_id": "exec_abc", "status": "running"}
        )
        with self._make_client() as client:
            result = client.run_workflow("wf_1", {"key": "val"})
            assert result["execution_id"] == "exec_abc"

        call_args = mock_request.call_args
        assert call_args.args[1] == "/orchestrator/workflows/wf_1/run"
        json_body = call_args.kwargs.get("json", {})
        assert json_body["inputs"] == {"key": "val"}

    @patch("httpx.Client.request")
    def test_run_workflow_no_inputs(self, mock_request):
        """Run with no inputs sends empty dict."""
        mock_request.return_value = self._mock_response(
            {"execution_id": "exec_abc"}
        )
        with self._make_client() as client:
            client.run_workflow("wf_1")

        call_args = mock_request.call_args
        json_body = call_args.kwargs.get("json", {})
        assert json_body["inputs"] == {}

    @patch("httpx.Client.request")
    def test_list_executions(self, mock_request):
        """List executions returns data."""
        mock_request.return_value = self._mock_response(
            {"executions": []}
        )
        with self._make_client() as client:
            result = client.list_executions()
            assert "executions" in result

        call_args = mock_request.call_args
        assert call_args.args[1] == "/orchestrator/executions"

    @patch("httpx.Client.request")
    def test_get_execution(self, mock_request):
        """Get execution returns status."""
        mock_request.return_value = self._mock_response(
            {"execution_id": "exec_1", "status": "completed"}
        )
        with self._make_client() as client:
            result = client.get_execution("exec_1")
            assert result["status"] == "completed"

        call_args = mock_request.call_args
        assert call_args.args[1] == "/orchestrator/executions/exec_1"

    @patch("httpx.Client.request")
    def test_get_steps(self, mock_request):
        """Get steps returns step array."""
        mock_request.return_value = self._mock_response(
            {"steps": [{"step_id": "s1", "status": "completed"}]}
        )
        with self._make_client() as client:
            result = client.get_steps("exec_1")
            assert len(result["steps"]) == 1

        call_args = mock_request.call_args
        assert call_args.args[1] == "/orchestrator/executions/exec_1/steps"

    @patch("httpx.Client.request")
    def test_stop_execution(self, mock_request):
        """Stop returns updated status."""
        mock_request.return_value = self._mock_response(
            {"execution_id": "exec_1", "status": "aborted"}
        )
        with self._make_client() as client:
            result = client.stop_execution("exec_1")
            assert result["status"] == "aborted"

        call_args = mock_request.call_args
        assert call_args.args[0] == "DELETE"
        assert call_args.args[1] == "/orchestrator/executions/exec_1"

    @patch("httpx.Client.request")
    def test_approve_step(self, mock_request):
        """Approve sends approved flag and reason."""
        mock_request.return_value = self._mock_response(
            {"status": "approved"}
        )
        with self._make_client() as client:
            result = client.approve_step("exec_1", "s1", True, "looks good")
            assert result["status"] == "approved"

        call_args = mock_request.call_args
        assert call_args.args[1] == "/orchestrator/executions/exec_1/steps/s1/approve"
        json_body = call_args.kwargs.get("json", {})
        assert json_body["approved"] is True
        assert json_body["reason"] == "looks good"

    @patch("httpx.Client.request")
    def test_approve_step_no_reason(self, mock_request):
        """Approve without reason omits reason field."""
        mock_request.return_value = self._mock_response({"status": "approved"})
        with self._make_client() as client:
            client.approve_step("exec_1", "s1", False)

        call_args = mock_request.call_args
        json_body = call_args.kwargs.get("json", {})
        assert json_body["approved"] is False
        assert "reason" not in json_body
