"""
Tests for database/queue_service.py

Tests cover:
- UserQueueService initialization
- Queue status management
- Task metadata operations
- Task status updates
- Pending task retrieval
- Task cleanup
"""

from unittest.mock import Mock
from datetime import datetime, UTC


class TestUserQueueServiceInit:
    """Tests for UserQueueService initialization."""

    def test_init_with_session(self):
        """Test initialization with a session."""
        from local_deep_research.database.queue_service import UserQueueService

        mock_session = Mock()
        service = UserQueueService(mock_session)

        assert service.session == mock_session


class TestUpdateQueueStatus:
    """Tests for update_queue_status method."""

    def test_updates_existing_status(self):
        """Test updating existing queue status."""
        from local_deep_research.database.queue_service import UserQueueService

        mock_session = Mock()
        mock_status = Mock()
        mock_session.query.return_value.first.return_value = mock_status

        service = UserQueueService(mock_session)
        service.update_queue_status(5, 10, "task-123")

        assert mock_status.active_tasks == 5
        assert mock_status.queued_tasks == 10
        assert mock_status.last_task_id == "task-123"
        mock_session.commit.assert_called_once()

    def test_creates_new_status_when_none_exists(self):
        """Test creating status when none exists."""
        from local_deep_research.database.queue_service import UserQueueService

        mock_session = Mock()
        mock_session.query.return_value.first.return_value = None

        service = UserQueueService(mock_session)
        service.update_queue_status(2, 5)

        mock_session.add.assert_called_once()
        mock_session.commit.assert_called_once()


class TestGetQueueStatus:
    """Tests for get_queue_status method."""

    def test_returns_status_dict(self):
        """Test returns status as dictionary."""
        from local_deep_research.database.queue_service import UserQueueService

        mock_session = Mock()
        mock_status = Mock()
        mock_status.active_tasks = 3
        mock_status.queued_tasks = 7
        mock_status.last_checked = datetime.now(UTC)
        mock_status.last_task_id = "task-456"
        mock_session.query.return_value.first.return_value = mock_status

        service = UserQueueService(mock_session)
        result = service.get_queue_status()

        assert result["active_tasks"] == 3
        assert result["queued_tasks"] == 7
        assert result["last_task_id"] == "task-456"

    def test_returns_none_when_no_status(self):
        """Test returns None when no status exists."""
        from local_deep_research.database.queue_service import UserQueueService

        mock_session = Mock()
        mock_session.query.return_value.first.return_value = None

        service = UserQueueService(mock_session)
        result = service.get_queue_status()

        assert result is None


class TestAddTaskMetadata:
    """Tests for add_task_metadata method."""

    def test_adds_task_metadata(self):
        """Test adding task metadata."""
        from local_deep_research.database.queue_service import UserQueueService

        mock_session = Mock()
        # Mock for _increment_queue_count
        mock_status = Mock()
        mock_status.queued_tasks = 0
        mock_session.query.return_value.first.return_value = mock_status

        service = UserQueueService(mock_session)
        service.add_task_metadata("task-1", "research", priority=5)

        mock_session.add.assert_called()
        mock_session.commit.assert_called()

    def test_increments_queue_count(self):
        """Test that queue count is incremented."""
        from local_deep_research.database.queue_service import UserQueueService

        mock_session = Mock()
        mock_status = Mock()
        mock_status.queued_tasks = 2
        mock_session.query.return_value.first.return_value = mock_status

        service = UserQueueService(mock_session)
        service.add_task_metadata("task-1", "research")

        assert mock_status.queued_tasks == 3


class TestUpdateTaskStatus:
    """Tests for update_task_status method."""

    def test_updates_task_to_processing(self):
        """Test updating task to processing status."""
        from local_deep_research.database.queue_service import UserQueueService

        mock_session = Mock()
        mock_task = Mock()
        mock_task.status = "queued"

        mock_status = Mock()
        mock_status.queued_tasks = 5
        mock_status.active_tasks = 2

        # Set up query chain
        mock_filter = Mock()
        mock_filter.first.return_value = mock_task
        mock_query = Mock()
        mock_query.filter_by.return_value = mock_filter
        mock_query.first.return_value = mock_status

        def query_side_effect(model):
            if hasattr(model, "task_id"):  # TaskMetadata
                return mock_query
            return Mock(first=Mock(return_value=mock_status))

        mock_session.query.side_effect = query_side_effect

        service = UserQueueService(mock_session)
        service.update_task_status("task-1", "processing")

        assert mock_task.status == "processing"

    def test_updates_task_to_completed(self):
        """Test updating task to completed status."""
        from local_deep_research.database.queue_service import UserQueueService

        mock_session = Mock()
        mock_task = Mock()
        mock_task.status = "processing"

        mock_status = Mock()
        mock_status.queued_tasks = 3
        mock_status.active_tasks = 2

        mock_filter = Mock()
        mock_filter.first.return_value = mock_task
        mock_query = Mock()
        mock_query.filter_by.return_value = mock_filter
        mock_query.first.return_value = mock_status

        def query_side_effect(model):
            if hasattr(model, "task_id"):
                return mock_query
            return Mock(first=Mock(return_value=mock_status))

        mock_session.query.side_effect = query_side_effect

        service = UserQueueService(mock_session)
        service.update_task_status("task-1", "completed")

        assert mock_task.status == "completed"

    def test_updates_task_with_error(self):
        """Test updating task with error message."""
        from local_deep_research.database.queue_service import UserQueueService

        mock_session = Mock()
        mock_task = Mock()
        mock_task.status = "processing"

        mock_status = Mock()
        mock_status.queued_tasks = 0
        mock_status.active_tasks = 1

        mock_filter = Mock()
        mock_filter.first.return_value = mock_task
        mock_query = Mock()
        mock_query.filter_by.return_value = mock_filter
        mock_query.first.return_value = mock_status

        def query_side_effect(model):
            if hasattr(model, "task_id"):
                return mock_query
            return Mock(first=Mock(return_value=mock_status))

        mock_session.query.side_effect = query_side_effect

        service = UserQueueService(mock_session)
        service.update_task_status("task-1", "failed", "Something went wrong")

        assert mock_task.status == "failed"
        assert mock_task.error_message == "Something went wrong"

    def test_handles_nonexistent_task(self):
        """Test handling when task doesn't exist."""
        from local_deep_research.database.queue_service import UserQueueService

        mock_session = Mock()
        mock_filter = Mock()
        mock_filter.first.return_value = None
        mock_query = Mock()
        mock_query.filter_by.return_value = mock_filter
        mock_session.query.return_value = mock_query

        service = UserQueueService(mock_session)
        # Should not raise
        service.update_task_status("nonexistent", "completed")


class TestGetPendingTasks:
    """Tests for get_pending_tasks method."""

    def test_returns_pending_tasks(self):
        """Test getting pending tasks."""
        from local_deep_research.database.queue_service import UserQueueService

        mock_session = Mock()
        mock_task1 = Mock()
        mock_task1.task_id = "task-1"
        mock_task1.task_type = "research"
        mock_task1.created_at = datetime.now(UTC)
        mock_task1.priority = 5

        mock_task2 = Mock()
        mock_task2.task_id = "task-2"
        mock_task2.task_type = "analysis"
        mock_task2.created_at = datetime.now(UTC)
        mock_task2.priority = 3

        mock_query = mock_session.query.return_value
        mock_query.filter_by.return_value.order_by.return_value.limit.return_value.all.return_value = [
            mock_task1,
            mock_task2,
        ]

        service = UserQueueService(mock_session)
        result = service.get_pending_tasks(limit=5)

        assert len(result) == 2
        assert result[0]["task_id"] == "task-1"
        assert result[0]["task_type"] == "research"
        assert result[1]["task_id"] == "task-2"

    def test_returns_empty_list_when_no_tasks(self):
        """Test returns empty list when no pending tasks."""
        from local_deep_research.database.queue_service import UserQueueService

        mock_session = Mock()
        mock_query = mock_session.query.return_value
        mock_query.filter_by.return_value.order_by.return_value.limit.return_value.all.return_value = []

        service = UserQueueService(mock_session)
        result = service.get_pending_tasks()

        assert result == []


class TestCleanupOldTasks:
    """Tests for cleanup_old_tasks method."""

    def test_deletes_old_tasks(self):
        """Test deleting old completed tasks."""
        from local_deep_research.database.queue_service import UserQueueService

        mock_session = Mock()
        mock_query = mock_session.query.return_value
        mock_query.filter.return_value.delete.return_value = 5

        service = UserQueueService(mock_session)
        result = service.cleanup_old_tasks(days=7)

        assert result == 5
        mock_session.commit.assert_called_once()


class TestGetTaskCounts:
    """Tests for task count methods."""

    def test_get_active_task_count(self):
        """Test getting active task count."""
        from local_deep_research.database.queue_service import UserQueueService

        mock_session = Mock()
        mock_status = Mock()
        mock_status.active_tasks = 3
        mock_session.query.return_value.first.return_value = mock_status

        service = UserQueueService(mock_session)
        result = service.get_active_task_count()

        assert result == 3

    def test_get_active_task_count_no_status(self):
        """Test getting active count when no status exists."""
        from local_deep_research.database.queue_service import UserQueueService

        mock_session = Mock()
        mock_session.query.return_value.first.return_value = None

        service = UserQueueService(mock_session)
        result = service.get_active_task_count()

        assert result == 0

    def test_get_queued_task_count(self):
        """Test getting queued task count."""
        from local_deep_research.database.queue_service import UserQueueService

        mock_session = Mock()
        mock_status = Mock()
        mock_status.queued_tasks = 7
        mock_session.query.return_value.first.return_value = mock_status

        service = UserQueueService(mock_session)
        result = service.get_queued_task_count()

        assert result == 7

    def test_get_queued_task_count_no_status(self):
        """Test getting queued count when no status exists."""
        from local_deep_research.database.queue_service import UserQueueService

        mock_session = Mock()
        mock_session.query.return_value.first.return_value = None

        service = UserQueueService(mock_session)
        result = service.get_queued_task_count()

        assert result == 0


class TestQueueCountHelpers:
    """Tests for queue count helper methods."""

    def test_increment_queue_count_existing(self):
        """Test incrementing queue count with existing status."""
        from local_deep_research.database.queue_service import UserQueueService

        mock_session = Mock()
        mock_status = Mock()
        mock_status.queued_tasks = 5
        mock_session.query.return_value.first.return_value = mock_status

        service = UserQueueService(mock_session)
        service._increment_queue_count()

        assert mock_status.queued_tasks == 6

    def test_increment_queue_count_new_status(self):
        """Test incrementing queue count creates new status."""
        from local_deep_research.database.queue_service import UserQueueService

        mock_session = Mock()
        mock_session.query.return_value.first.return_value = None

        service = UserQueueService(mock_session)
        service._increment_queue_count()

        mock_session.add.assert_called_once()

    def test_update_queue_counts_clamps_to_zero(self):
        """Test that queue counts don't go below zero."""
        from local_deep_research.database.queue_service import UserQueueService

        mock_session = Mock()
        mock_status = Mock()
        mock_status.queued_tasks = 1
        mock_status.active_tasks = 1
        mock_session.query.return_value.first.return_value = mock_status

        service = UserQueueService(mock_session)
        service._update_queue_counts(-5, -5)

        assert mock_status.queued_tasks == 0
        assert mock_status.active_tasks == 0
