"""Integration tests for PM3 API endpoints.

Tests the refactored PM3 API endpoints to ensure:
- Proper integration with PM3Service
- Correct HTTP status codes for different error types
- Request/response format consistency
- Session management integration
"""
import pytest
from fastapi.testclient import TestClient
from unittest.mock import patch, AsyncMock, Mock

from app.backend.services.pm3_service import PM3ServiceResult, PM3ServiceError


class TestPM3APIStatus:
    """Test /api/pm3/status endpoint."""

    def test_get_status_success(self, test_client, mock_pm3_service):
        """Test successful status retrieval."""
        # Arrange
        mock_pm3_service.get_status.return_value = PM3ServiceResult(
            success=True,
            data={
                "connected": True,
                "device_path": "/dev/ttyACM0",
                "version": "Proxmark3 v4.0",
                "session_active": False
            }
        )

        # Act
        with patch('app.backend.api.pm3.container') as mock_container:
            mock_container.pm3_service = mock_pm3_service
            response = test_client.get("/api/pm3/status")

        # Assert
        assert response.status_code == 200
        data = response.json()
        assert data["connected"] is True
        assert data["device"] == "/dev/ttyACM0"
        assert "Proxmark3" in data["version"]

    def test_get_status_error(self, test_client, mock_pm3_service):
        """Test status retrieval with error."""
        # Arrange
        mock_pm3_service.get_status.return_value = PM3ServiceResult(
            success=False,
            error=PM3ServiceError(
                code="status_error",
                message="Failed to query status"
            )
        )

        # Act
        with patch('app.backend.api.pm3.container') as mock_container:
            mock_container.pm3_service = mock_pm3_service
            response = test_client.get("/api/pm3/status")

        # Assert
        assert response.status_code == 500
        assert "Failed to query status" in response.json()["detail"]


class TestPM3APICommand:
    """Test /api/pm3/command endpoint."""

    def test_execute_command_success(self, test_client, mock_pm3_service):
        """Test successful command execution."""
        # Arrange
        mock_pm3_service.execute_command.return_value = PM3ServiceResult(
            success=True,
            data={
                "output": "Proxmark3 RFID instrument",
                "command": "hw version",
                "session_id": "test-session"
            }
        )

        # Act
        with patch('app.backend.api.pm3.container') as mock_container:
            mock_container.pm3_service = mock_pm3_service
            response = test_client.post(
                "/api/pm3/command",
                json={"command": "hw version", "session_id": "test-session"}
            )

        # Assert
        assert response.status_code == 200
        data = response.json()
        assert data["success"] is True
        assert "Proxmark3" in data["output"]
        assert data["error"] is None

    def test_execute_command_session_locked(self, test_client, mock_pm3_service):
        """Test command execution with session locked."""
        # Arrange
        mock_pm3_service.execute_command.return_value = PM3ServiceResult(
            success=False,
            error=PM3ServiceError(
                code="session_locked",
                message="Another session is active"
            )
        )

        # Act
        with patch('app.backend.api.pm3.container') as mock_container:
            mock_container.pm3_service = mock_pm3_service
            response = test_client.post(
                "/api/pm3/command",
                json={"command": "hw version", "session_id": "test-session"}
            )

        # Assert
        assert response.status_code == 423  # Locked
        assert "Another session is active" in response.json()["detail"]

    def test_execute_command_pm3_not_connected(self, test_client, mock_pm3_service):
        """Test command execution when PM3 not connected."""
        # Arrange
        mock_pm3_service.execute_command.return_value = PM3ServiceResult(
            success=False,
            error=PM3ServiceError(
                code="pm3_not_connected",
                message="Proxmark3 not connected"
            )
        )

        # Act
        with patch('app.backend.api.pm3.container') as mock_container:
            mock_container.pm3_service = mock_pm3_service
            response = test_client.post(
                "/api/pm3/command",
                json={"command": "hw version"}
            )

        # Assert
        assert response.status_code == 200  # Returns in body, not HTTP error
        data = response.json()
        assert data["success"] is False
        assert "not connected" in data["error"].lower()


class TestPM3APIConnection:
    """Test PM3 connection endpoints."""

    def test_connect_success(self, test_client, mock_pm3_service):
        """Test successful PM3 connection."""
        # Arrange
        mock_pm3_service.connect.return_value = PM3ServiceResult(
            success=True,
            data={"message": "Connected to Proxmark3"}
        )

        # Act
        with patch('app.backend.api.pm3.container') as mock_container:
            mock_container.pm3_service = mock_pm3_service
            response = test_client.post("/api/pm3/connect")

        # Assert
        assert response.status_code == 200
        assert response.json()["success"] is True

    def test_connect_failure(self, test_client, mock_pm3_service):
        """Test PM3 connection failure."""
        # Arrange
        mock_pm3_service.connect.return_value = PM3ServiceResult(
            success=False,
            error=PM3ServiceError(
                code="connection_error",
                message="Device not found"
            )
        )

        # Act
        with patch('app.backend.api.pm3.container') as mock_container:
            mock_container.pm3_service = mock_pm3_service
            response = test_client.post("/api/pm3/connect")

        # Assert
        assert response.status_code == 503
        assert "Device not found" in response.json()["detail"]

    def test_disconnect_success(self, test_client, mock_pm3_service):
        """Test successful PM3 disconnection."""
        # Arrange
        mock_pm3_service.disconnect.return_value = PM3ServiceResult(
            success=True,
            data={"message": "Disconnected from Proxmark3"}
        )

        # Act
        with patch('app.backend.api.pm3.container') as mock_container:
            mock_container.pm3_service = mock_pm3_service
            response = test_client.post("/api/pm3/disconnect")

        # Assert
        assert response.status_code == 200
        assert response.json()["success"] is True
