# tests/tasks/test_celery_config.py
"""
Tests for Celery application configuration.

These tests verify:
- Celery app is properly configured
- Queue routing is correctly set up per ADR-003
- Task discovery works for all task modules
- Beat schedule is configured for periodic tasks
"""



class TestCeleryAppConfiguration:
    """Tests for the Celery application instance configuration."""

    def test_celery_app_is_created_with_correct_name(self):
        """Test that the Celery app is created with 'syndarix' as the name."""
        from app.celery_app import celery_app

        assert celery_app.main == "syndarix"

    def test_celery_app_uses_redis_broker(self):
        """Test that Celery is configured to use Redis as the broker."""
        from app.celery_app import celery_app
        from app.core.config import settings

        # The broker URL should match the settings
        assert celery_app.conf.broker_url == settings.celery_broker_url

    def test_celery_app_uses_redis_backend(self):
        """Test that Celery is configured to use Redis as the result backend."""
        from app.celery_app import celery_app
        from app.core.config import settings

        assert celery_app.conf.result_backend == settings.celery_result_backend

    def test_celery_uses_json_serialization(self):
        """Test that Celery is configured to use JSON for serialization."""
        from app.celery_app import celery_app

        assert celery_app.conf.task_serializer == "json"
        assert celery_app.conf.result_serializer == "json"
        assert "json" in celery_app.conf.accept_content

    def test_celery_uses_utc_timezone(self):
        """Test that Celery is configured to use UTC timezone."""
        from app.celery_app import celery_app

        assert celery_app.conf.timezone == "UTC"
        assert celery_app.conf.enable_utc is True

    def test_celery_has_late_ack_enabled(self):
        """Test that late acknowledgment is enabled for task reliability."""
        from app.celery_app import celery_app

        # Per ADR-003: Late ack for reliability
        assert celery_app.conf.task_acks_late is True
        assert celery_app.conf.task_reject_on_worker_lost is True

    def test_celery_prefetch_multiplier_is_one(self):
        """Test that worker prefetch is set to 1 for fair task distribution."""
        from app.celery_app import celery_app

        assert celery_app.conf.worker_prefetch_multiplier == 1

    def test_celery_result_expiration(self):
        """Test that results expire after 24 hours."""
        from app.celery_app import celery_app

        # 86400 seconds = 24 hours
        assert celery_app.conf.result_expires == 86400

    def test_celery_has_time_limits_configured(self):
        """Test that task time limits are configured per ADR-003."""
        from app.celery_app import celery_app

        # 5 minutes soft limit, 10 minutes hard limit
        assert celery_app.conf.task_soft_time_limit == 300
        assert celery_app.conf.task_time_limit == 600

    def test_celery_broker_connection_retry_enabled(self):
        """Test that broker connection retry is enabled on startup."""
        from app.celery_app import celery_app

        assert celery_app.conf.broker_connection_retry_on_startup is True


class TestQueueRoutingConfiguration:
    """Tests for Celery queue routing configuration per ADR-003."""

    def test_default_queue_is_configured(self):
        """Test that 'default' is set as the default queue."""
        from app.celery_app import celery_app

        assert celery_app.conf.task_default_queue == "default"

    def test_task_routes_are_configured(self):
        """Test that task routes are properly configured."""
        from app.celery_app import celery_app

        routes = celery_app.conf.task_routes
        assert routes is not None
        assert isinstance(routes, dict)

    def test_agent_tasks_routed_to_agent_queue(self):
        """Test that agent tasks are routed to the 'agent' queue."""
        from app.celery_app import celery_app

        routes = celery_app.conf.task_routes
        assert "app.tasks.agent.*" in routes
        assert routes["app.tasks.agent.*"]["queue"] == "agent"

    def test_git_tasks_routed_to_git_queue(self):
        """Test that git tasks are routed to the 'git' queue."""
        from app.celery_app import celery_app

        routes = celery_app.conf.task_routes
        assert "app.tasks.git.*" in routes
        assert routes["app.tasks.git.*"]["queue"] == "git"

    def test_sync_tasks_routed_to_sync_queue(self):
        """Test that sync tasks are routed to the 'sync' queue."""
        from app.celery_app import celery_app

        routes = celery_app.conf.task_routes
        assert "app.tasks.sync.*" in routes
        assert routes["app.tasks.sync.*"]["queue"] == "sync"

    def test_default_tasks_routed_to_default_queue(self):
        """Test that unmatched tasks are routed to the 'default' queue."""
        from app.celery_app import celery_app

        routes = celery_app.conf.task_routes
        assert "app.tasks.*" in routes
        assert routes["app.tasks.*"]["queue"] == "default"

    def test_all_queues_are_defined(self):
        """Test that all expected queues are defined in task_queues."""
        from app.celery_app import celery_app

        queues = celery_app.conf.task_queues
        expected_queues = {"agent", "git", "sync", "default"}

        assert queues is not None
        assert set(queues.keys()) == expected_queues

    def test_queue_exchanges_are_configured(self):
        """Test that each queue has its own exchange configured."""
        from app.celery_app import celery_app

        queues = celery_app.conf.task_queues

        for queue_name in ["agent", "git", "sync", "default"]:
            assert queue_name in queues
            assert queues[queue_name]["exchange"] == queue_name
            assert queues[queue_name]["routing_key"] == queue_name


class TestTaskDiscovery:
    """Tests for Celery task auto-discovery."""

    def test_task_imports_are_configured(self):
        """Test that task imports are configured for auto-discovery."""
        from app.celery_app import celery_app

        imports = celery_app.conf.imports
        assert imports is not None
        assert "app.tasks" in imports

    def test_agent_tasks_are_discoverable(self):
        """Test that agent tasks can be discovered and accessed."""
        # Force task registration by importing
        import app.tasks.agent  # noqa: F401
        from app.celery_app import celery_app

        # Check that agent tasks are registered
        registered_tasks = celery_app.tasks

        assert "app.tasks.agent.run_agent_step" in registered_tasks
        assert "app.tasks.agent.spawn_agent" in registered_tasks
        assert "app.tasks.agent.terminate_agent" in registered_tasks

    def test_git_tasks_are_discoverable(self):
        """Test that git tasks can be discovered and accessed."""
        # Force task registration by importing
        import app.tasks.git  # noqa: F401
        from app.celery_app import celery_app

        registered_tasks = celery_app.tasks

        assert "app.tasks.git.clone_repository" in registered_tasks
        assert "app.tasks.git.commit_changes" in registered_tasks
        assert "app.tasks.git.create_branch" in registered_tasks
        assert "app.tasks.git.create_pull_request" in registered_tasks
        assert "app.tasks.git.push_changes" in registered_tasks

    def test_sync_tasks_are_discoverable(self):
        """Test that sync tasks can be discovered and accessed."""
        # Force task registration by importing
        import app.tasks.sync  # noqa: F401
        from app.celery_app import celery_app

        registered_tasks = celery_app.tasks

        assert "app.tasks.sync.sync_issues_incremental" in registered_tasks
        assert "app.tasks.sync.sync_issues_full" in registered_tasks
        assert "app.tasks.sync.process_webhook_event" in registered_tasks
        assert "app.tasks.sync.sync_project_issues" in registered_tasks
        assert "app.tasks.sync.push_issue_to_external" in registered_tasks

    def test_workflow_tasks_are_discoverable(self):
        """Test that workflow tasks can be discovered and accessed."""
        # Force task registration by importing
        import app.tasks.workflow  # noqa: F401
        from app.celery_app import celery_app

        registered_tasks = celery_app.tasks

        assert "app.tasks.workflow.recover_stale_workflows" in registered_tasks
        assert "app.tasks.workflow.execute_workflow_step" in registered_tasks
        assert "app.tasks.workflow.handle_approval_response" in registered_tasks
        assert "app.tasks.workflow.start_sprint_workflow" in registered_tasks
        assert "app.tasks.workflow.start_story_workflow" in registered_tasks

    def test_cost_tasks_are_discoverable(self):
        """Test that cost tasks can be discovered and accessed."""
        # Force task registration by importing
        import app.tasks.cost  # noqa: F401
        from app.celery_app import celery_app

        registered_tasks = celery_app.tasks

        assert "app.tasks.cost.aggregate_daily_costs" in registered_tasks
        assert "app.tasks.cost.check_budget_thresholds" in registered_tasks
        assert "app.tasks.cost.record_llm_usage" in registered_tasks
        assert "app.tasks.cost.generate_cost_report" in registered_tasks
        assert "app.tasks.cost.reset_daily_budget_counters" in registered_tasks


class TestBeatSchedule:
    """Tests for Celery Beat scheduled tasks configuration."""

    def test_beat_schedule_is_configured(self):
        """Test that beat_schedule is configured."""
        from app.celery_app import celery_app

        assert celery_app.conf.beat_schedule is not None
        assert isinstance(celery_app.conf.beat_schedule, dict)

    def test_incremental_sync_is_scheduled(self):
        """Test that incremental issue sync is scheduled per ADR-011."""
        from app.celery_app import celery_app

        schedule = celery_app.conf.beat_schedule
        assert "sync-issues-incremental" in schedule

        task_config = schedule["sync-issues-incremental"]
        assert task_config["task"] == "app.tasks.sync.sync_issues_incremental"
        assert task_config["schedule"] == 60.0  # Every 60 seconds

    def test_full_sync_is_scheduled(self):
        """Test that full issue sync is scheduled per ADR-011."""
        from app.celery_app import celery_app

        schedule = celery_app.conf.beat_schedule
        assert "sync-issues-full" in schedule

        task_config = schedule["sync-issues-full"]
        assert task_config["task"] == "app.tasks.sync.sync_issues_full"
        assert task_config["schedule"] == 900.0  # Every 15 minutes

    def test_stale_workflow_recovery_is_scheduled(self):
        """Test that stale workflow recovery is scheduled per ADR-007."""
        from app.celery_app import celery_app

        schedule = celery_app.conf.beat_schedule
        assert "recover-stale-workflows" in schedule

        task_config = schedule["recover-stale-workflows"]
        assert task_config["task"] == "app.tasks.workflow.recover_stale_workflows"
        assert task_config["schedule"] == 300.0  # Every 5 minutes

    def test_daily_cost_aggregation_is_scheduled(self):
        """Test that daily cost aggregation is scheduled per ADR-012."""
        from app.celery_app import celery_app

        schedule = celery_app.conf.beat_schedule
        assert "aggregate-daily-costs" in schedule

        task_config = schedule["aggregate-daily-costs"]
        assert task_config["task"] == "app.tasks.cost.aggregate_daily_costs"
        assert task_config["schedule"] == 3600.0  # Every hour


class TestTaskModuleExports:
    """Tests for the task module __init__.py exports."""

    def test_tasks_package_exports_all_modules(self):
        """Test that the tasks package exports all task modules."""
        from app import tasks

        assert hasattr(tasks, "agent")
        assert hasattr(tasks, "git")
        assert hasattr(tasks, "sync")
        assert hasattr(tasks, "workflow")
        assert hasattr(tasks, "cost")

    def test_tasks_all_attribute_is_correct(self):
        """Test that __all__ contains all expected module names."""
        from app import tasks

        expected_modules = ["agent", "git", "sync", "workflow", "cost"]
        assert set(tasks.__all__) == set(expected_modules)
