"""Integration tests for Virtual Printer API endpoints.

Tests the full request/response cycle for /api/v1/settings/virtual-printer endpoints.
"""

from unittest.mock import AsyncMock, MagicMock, patch

import pytest
from httpx import AsyncClient


class TestVirtualPrinterSettingsAPI:
    """Integration tests for /api/v1/settings/virtual-printer endpoints."""

    # ========================================================================
    # Get settings
    # ========================================================================

    @pytest.mark.asyncio
    @pytest.mark.integration
    async def test_get_virtual_printer_settings(self, async_client: AsyncClient):
        """Verify virtual printer settings can be retrieved."""
        response = await async_client.get("/api/v1/settings/virtual-printer")

        assert response.status_code == 200
        result = response.json()
        assert "enabled" in result
        assert "access_code_set" in result
        assert "mode" in result
        assert "status" in result

    @pytest.mark.asyncio
    @pytest.mark.integration
    async def test_get_settings_has_status(self, async_client: AsyncClient):
        """Verify settings include status details."""
        response = await async_client.get("/api/v1/settings/virtual-printer")

        assert response.status_code == 200
        result = response.json()
        status = result["status"]
        assert "enabled" in status
        assert "running" in status
        assert "mode" in status
        assert "name" in status
        assert "serial" in status
        assert "pending_files" in status

    # ========================================================================
    # Update settings
    # ========================================================================

    @pytest.mark.asyncio
    @pytest.mark.integration
    async def test_update_mode(self, async_client: AsyncClient):
        """Verify mode can be updated."""
        response = await async_client.put("/api/v1/settings/virtual-printer?mode=review")

        assert response.status_code == 200
        result = response.json()
        assert result["mode"] == "review"

    @pytest.mark.asyncio
    @pytest.mark.integration
    async def test_update_mode_to_print_queue(self, async_client: AsyncClient):
        """Verify mode can be set to print_queue."""
        response = await async_client.put("/api/v1/settings/virtual-printer?mode=print_queue")

        assert response.status_code == 200
        result = response.json()
        assert result["mode"] == "print_queue"

    @pytest.mark.asyncio
    @pytest.mark.integration
    async def test_update_mode_legacy_queue_maps_to_review(self, async_client: AsyncClient):
        """Verify legacy 'queue' mode is normalized to 'review'."""
        response = await async_client.put("/api/v1/settings/virtual-printer?mode=queue")

        assert response.status_code == 200
        result = response.json()
        assert result["mode"] == "review"  # Legacy queue maps to review

    @pytest.mark.asyncio
    @pytest.mark.integration
    async def test_update_mode_to_immediate(self, async_client: AsyncClient):
        """Verify mode can be set to immediate."""
        response = await async_client.put("/api/v1/settings/virtual-printer?mode=immediate")

        assert response.status_code == 200
        result = response.json()
        assert result["mode"] == "immediate"

    @pytest.mark.asyncio
    @pytest.mark.integration
    async def test_update_access_code(self, async_client: AsyncClient):
        """Verify access code can be set."""
        response = await async_client.put("/api/v1/settings/virtual-printer?access_code=12345678")

        assert response.status_code == 200
        result = response.json()
        assert result["access_code_set"] is True

    @pytest.mark.asyncio
    @pytest.mark.integration
    async def test_update_access_code_wrong_length(self, async_client: AsyncClient):
        """Verify access code validation for length."""
        response = await async_client.put("/api/v1/settings/virtual-printer?access_code=123")

        # Should fail validation
        assert response.status_code == 400

    @pytest.mark.asyncio
    @pytest.mark.integration
    async def test_enable_without_access_code(self, async_client: AsyncClient):
        """Verify enabling fails without access code set."""
        # First ensure no access code is set by checking current state
        # Then try to enable
        response = await async_client.put("/api/v1/settings/virtual-printer?enabled=true")

        # If access code wasn't set, this should fail
        # If it was already set, it will succeed
        # Both are valid test outcomes
        assert response.status_code in [200, 400]

    @pytest.mark.asyncio
    @pytest.mark.integration
    async def test_enable_with_access_code(self, async_client: AsyncClient):
        """Verify enabling succeeds when access code is set."""
        # First set access code
        await async_client.put("/api/v1/settings/virtual-printer?access_code=12345678")

        # Then enable (this will start the servers which may fail in test env)
        # We mock the manager to avoid actually starting servers
        with patch("backend.app.services.virtual_printer.virtual_printer_manager") as mock_manager:
            mock_manager.configure = AsyncMock()
            mock_manager.get_status = MagicMock(
                return_value={
                    "enabled": True,
                    "running": True,
                    "mode": "immediate",
                    "name": "Bambuddy",
                    "serial": "00M09A391800001",
                    "pending_files": 0,
                }
            )

            response = await async_client.put("/api/v1/settings/virtual-printer?enabled=true")

            assert response.status_code == 200

    @pytest.mark.asyncio
    @pytest.mark.integration
    async def test_disable_virtual_printer(self, async_client: AsyncClient):
        """Verify virtual printer can be disabled."""
        with patch("backend.app.services.virtual_printer.virtual_printer_manager") as mock_manager:
            mock_manager.configure = AsyncMock()
            mock_manager.get_status = MagicMock(
                return_value={
                    "enabled": False,
                    "running": False,
                    "mode": "immediate",
                    "name": "Bambuddy",
                    "serial": "00M09A391800001",
                    "pending_files": 0,
                }
            )

            response = await async_client.put("/api/v1/settings/virtual-printer?enabled=false")

            assert response.status_code == 200
            result = response.json()
            assert result["enabled"] is False


class TestPendingUploadsAPI:
    """Integration tests for /api/v1/pending-uploads/ endpoints."""

    @pytest.fixture
    def mock_pending_uploads(self, db_session):
        """Create mock pending uploads in database."""

        async def _create_pending(filename: str = "test.3mf"):
            from datetime import datetime

            from backend.app.models.pending_upload import PendingUpload

            upload = PendingUpload(
                filename=filename,
                file_path=f"/tmp/{filename}",
                file_size=1024,
                source_ip="192.168.1.100",
                status="pending",
            )
            db_session.add(upload)
            await db_session.commit()
            await db_session.refresh(upload)
            return upload

        return _create_pending

    # ========================================================================
    # List pending uploads
    # ========================================================================

    @pytest.mark.asyncio
    @pytest.mark.integration
    async def test_list_pending_uploads_empty(self, async_client: AsyncClient):
        """Verify empty list is returned when no pending uploads."""
        response = await async_client.get("/api/v1/pending-uploads/")

        assert response.status_code == 200
        result = response.json()
        assert isinstance(result, list)

    @pytest.mark.asyncio
    @pytest.mark.integration
    async def test_get_pending_uploads_count(self, async_client: AsyncClient):
        """Verify count endpoint returns correct count."""
        response = await async_client.get("/api/v1/pending-uploads/count")

        assert response.status_code == 200
        result = response.json()
        assert "count" in result
        assert isinstance(result["count"], int)

    # ========================================================================
    # Archive pending upload
    # ========================================================================

    @pytest.mark.asyncio
    @pytest.mark.integration
    async def test_archive_nonexistent_upload(self, async_client: AsyncClient):
        """Verify archiving non-existent upload returns 404."""
        response = await async_client.post("/api/v1/pending-uploads/99999/archive")

        assert response.status_code == 404

    # ========================================================================
    # Discard pending upload
    # ========================================================================

    @pytest.mark.asyncio
    @pytest.mark.integration
    async def test_discard_nonexistent_upload(self, async_client: AsyncClient):
        """Verify discarding non-existent upload returns 404."""
        response = await async_client.delete("/api/v1/pending-uploads/99999")

        assert response.status_code == 404

    # ========================================================================
    # Bulk operations
    # ========================================================================

    @pytest.mark.asyncio
    @pytest.mark.integration
    async def test_archive_all_empty(self, async_client: AsyncClient):
        """Verify archive all with no pending uploads."""
        response = await async_client.post("/api/v1/pending-uploads/archive-all")

        assert response.status_code == 200
        result = response.json()
        assert "archived" in result
        assert "failed" in result

    @pytest.mark.asyncio
    @pytest.mark.integration
    async def test_discard_all_empty(self, async_client: AsyncClient):
        """Verify discard all with no pending uploads."""
        response = await async_client.delete("/api/v1/pending-uploads/discard-all")

        assert response.status_code == 200
        result = response.json()
        assert "discarded" in result
