"""
Tests for service layer components.
"""

from unittest.mock import AsyncMock, MagicMock, patch

import pytest

from app.services.aws_service import AWSService
from app.services.health import HealthService
from app.services.queue_processor import QueueProcessor


class TestHealthService:
    """Test the HealthService class."""

    @pytest.mark.asyncio
    async def test_check_database_success(self):
        """Test successful database health check."""
        service = HealthService()

        with patch("app.services.health.AIFeedbackQueue") as mock_queue:
            # Mock the all method to return a mock object with count method
            mock_all = MagicMock()
            mock_all.count = AsyncMock(return_value=5)
            mock_queue.all.return_value = mock_all

            result = await service._check_database()

            assert result["healthy"] is True
            assert "Database connection successful" in result["message"]
            assert "timestamp" in result

    @pytest.mark.asyncio
    async def test_check_database_failure(self):
        """Test failed database health check."""
        service = HealthService()

        with patch("app.models.queue.AIFeedbackQueue") as mock_queue:
            mock_queue.all.return_value.count = AsyncMock(
                side_effect=Exception("Connection failed")
            )

            result = await service._check_database()

            assert result["healthy"] is False
            assert "Database connection failed" in result["message"]
            assert "timestamp" in result

    @pytest.mark.asyncio
    async def test_check_aws(self):
        """Test AWS health check."""
        service = HealthService()

        result = await service._check_aws()

        assert result["healthy"] is True
        assert "AWS connection successful" in result["message"]
        assert "timestamp" in result

    @pytest.mark.asyncio
    async def test_check_queue_success(self):
        """Test successful queue health check."""
        service = HealthService()

        with patch("app.services.health.AIFeedbackQueue") as mock_queue:
            # Mock the filter method to return a mock object with count method
            mock_filter = MagicMock()
            mock_filter.count = AsyncMock(side_effect=[2, 1, 0, 3])
            mock_queue.filter.return_value = mock_filter

            result = await service._check_queue()

            assert result["healthy"] is True
            assert "Queue status check successful" in result["message"]
            assert "stats" in result
            assert result["stats"]["0"] == 2
            assert result["stats"]["1"] == 1
            assert result["stats"]["2"] == 0
            assert result["stats"]["3"] == 3

    @pytest.mark.asyncio
    async def test_check_queue_failure(self):
        """Test failed queue health check."""
        service = HealthService()

        with patch("app.models.queue.AIFeedbackQueue") as mock_queue:
            mock_queue.filter.return_value.count = AsyncMock(
                side_effect=Exception("Queue error")
            )

            result = await service._check_queue()

            assert result["healthy"] is False
            assert "Queue status check failed" in result["message"]
            assert "timestamp" in result

    @pytest.mark.asyncio
    async def test_check_all_success(self):
        """Test successful comprehensive health check."""
        service = HealthService()

        with (
            patch.object(service, "_check_database") as mock_db,
            patch.object(service, "_check_aws") as mock_aws,
            patch.object(service, "_check_queue") as mock_queue,
        ):
            mock_db.return_value = {"healthy": True, "message": "DB OK"}
            mock_aws.return_value = {"healthy": True, "message": "AWS OK"}
            mock_queue.return_value = {"healthy": True, "message": "Queue OK"}

            result = await service.check_all()

            assert result["status"] == "healthy"
            assert "timestamp" in result
            assert "checks" in result
            assert result["checks"]["database"]["healthy"] is True
            assert result["checks"]["aws"]["healthy"] is True
            assert result["checks"]["queue"]["healthy"] is True

    @pytest.mark.asyncio
    async def test_is_ready_success(self):
        """Test successful readiness check."""
        service = HealthService()

        with (
            patch.object(service, "_check_database") as mock_db,
            patch.object(service, "_check_queue") as mock_queue,
        ):
            mock_db.return_value = {"healthy": True}
            mock_queue.return_value = {"healthy": True}

            result = await service.is_ready()
            assert result is True

    @pytest.mark.asyncio
    async def test_is_ready_database_failure(self):
        """Test readiness check with database failure."""
        service = HealthService()

        with (
            patch.object(service, "_check_database") as mock_db,
            patch.object(service, "_check_queue") as mock_queue,
        ):
            mock_db.return_value = {"healthy": False}
            mock_queue.return_value = {"healthy": True}

            result = await service.is_ready()
            assert result is False

    @pytest.mark.asyncio
    async def test_is_ready_queue_failure(self):
        """Test readiness check with queue failure."""
        service = HealthService()

        with (
            patch.object(service, "_check_database") as mock_db,
            patch.object(service, "_check_queue") as mock_queue,
        ):
            mock_db.return_value = {"healthy": True}
            mock_queue.return_value = {"healthy": False}

            result = await service.is_ready()
            assert result is False


class TestAWSService:
    """Test the AWSService class."""

    def test_aws_service_creation(self):
        """Test AWSService can be instantiated."""
        service = AWSService()
        assert service is not None

    @pytest.mark.asyncio
    async def test_download_file_success(self):
        """Test successful file download."""
        service = AWSService()

        with patch("aioboto3.Session") as mock_session:
            mock_session_instance = MagicMock()
            mock_session.return_value = mock_session_instance
            mock_session_instance.client.return_value.__aenter__.return_value = (
                MagicMock()
            )

            result = await service.download_file(
                "test-bucket", "test-key", "local-path"
            )

            assert isinstance(result, bool)

    @pytest.mark.asyncio
    async def test_check_file_exists_success(self):
        """Test successful file existence check."""
        service = AWSService()

        with patch("aioboto3.Session") as mock_session:
            mock_session_instance = MagicMock()
            mock_session.return_value = mock_session_instance
            mock_session_instance.client.return_value.__aenter__.return_value = (
                MagicMock()
            )

            result = await service.check_file_exists("test-key")

            assert isinstance(result, bool)

    @pytest.mark.asyncio
    async def test_initialize_clients_success(self):
        """Test successful client initialization."""
        service = AWSService()

        with patch("aioboto3.Session") as mock_session:
            mock_session_instance = MagicMock()
            mock_session.return_value = mock_session_instance

            result = await service.initialize_clients()

            assert isinstance(result, bool)


class TestQueueProcessor:
    """Test the QueueProcessor class."""

    def test_queue_processor_creation(self):
        """Test QueueProcessor can be instantiated."""
        service = QueueProcessor()
        assert service is not None
        assert hasattr(service, "max_concurrent_jobs")
        assert hasattr(service, "video_processor")
        assert hasattr(service, "audio_processor")

    @pytest.mark.asyncio
    async def test_check_and_update_file_availability(self):
        """Test file availability check."""
        service = QueueProcessor()

        with patch.object(service.aws_service, "check_file_exists") as mock_check:
            mock_check.return_value = True

            result = await service.check_and_update_file_availability()

            assert isinstance(result, dict)
            assert "status" in result

    @pytest.mark.asyncio
    async def test_get_queue_status(self):
        """Test getting queue status."""
        service = QueueProcessor()

        result = await service.get_queue_status()

        assert isinstance(result, dict)
        assert "active_jobs_count" in result
        assert "available_slots" in result
