"""Tests for Tower dashboard route (/tower)."""

from unittest.mock import MagicMock, patch


def _mock_spark_engine():
    """Return a mock spark_engine with realistic return values."""
    engine = MagicMock()

    engine.status.return_value = {
        "enabled": True,
        "events_captured": 5,
        "memories_stored": 3,
        "predictions": {"total": 2, "avg_accuracy": 0.85},
        "event_types": {
            "task_posted": 2,
            "bid_submitted": 1,
            "task_assigned": 1,
            "task_completed": 1,
            "task_failed": 0,
            "agent_joined": 0,
            "tool_executed": 0,
            "creative_step": 0,
        },
    }

    event = MagicMock()
    event.event_type = "task_completed"
    event.description = "Task finished"
    event.importance = 0.8
    event.created_at = "2026-01-01T00:00:00"
    event.agent_id = "agent-1234-abcd"
    event.task_id = "task-5678-efgh"
    event.data = '{"result": "ok"}'
    engine.get_timeline.return_value = [event]

    pred = MagicMock()
    pred.task_id = "task-5678-efgh"
    pred.accuracy = 0.9
    pred.evaluated_at = "2026-01-01T01:00:00"
    pred.created_at = "2026-01-01T00:30:00"
    pred.predicted_value = '{"outcome": "success"}'
    engine.get_predictions.return_value = [pred]

    advisory = MagicMock()
    advisory.category = "performance"
    advisory.priority = "high"
    advisory.title = "Slow tasks"
    advisory.detail = "Tasks taking longer than expected"
    advisory.suggested_action = "Scale up workers"
    engine.get_advisories.return_value = [advisory]

    return engine


class TestTowerUI:
    """Tests for GET /tower endpoint."""

    @patch("dashboard.routes.tower.spark_engine", new_callable=_mock_spark_engine)
    def test_tower_returns_200(self, mock_engine, client):
        response = client.get("/tower")
        assert response.status_code == 200

    @patch("dashboard.routes.tower.spark_engine", new_callable=_mock_spark_engine)
    def test_tower_returns_html(self, mock_engine, client):
        response = client.get("/tower")
        assert "text/html" in response.headers["content-type"]

    @patch("dashboard.routes.tower.spark_engine", new_callable=_mock_spark_engine)
    def test_tower_contains_dashboard_content(self, mock_engine, client):
        response = client.get("/tower")
        body = response.text
        assert "tower" in body.lower() or "spark" in body.lower()


class TestSparkSnapshot:
    """Tests for _spark_snapshot helper."""

    @patch("dashboard.routes.tower.spark_engine", new_callable=_mock_spark_engine)
    def test_snapshot_structure(self, mock_engine):
        from dashboard.routes.tower import _spark_snapshot

        snap = _spark_snapshot()
        assert snap["type"] == "spark_state"
        assert "status" in snap
        assert "events" in snap
        assert "predictions" in snap
        assert "advisories" in snap

    @patch("dashboard.routes.tower.spark_engine", new_callable=_mock_spark_engine)
    def test_snapshot_events_parsed(self, mock_engine):
        from dashboard.routes.tower import _spark_snapshot

        snap = _spark_snapshot()
        ev = snap["events"][0]
        assert ev["event_type"] == "task_completed"
        assert ev["importance"] == 0.8
        assert ev["agent_id"] == "agent-12"
        assert ev["task_id"] == "task-567"
        assert ev["data"] == {"result": "ok"}

    @patch("dashboard.routes.tower.spark_engine", new_callable=_mock_spark_engine)
    def test_snapshot_predictions_parsed(self, mock_engine):
        from dashboard.routes.tower import _spark_snapshot

        snap = _spark_snapshot()
        pred = snap["predictions"][0]
        assert pred["task_id"] == "task-567"
        assert pred["accuracy"] == 0.9
        assert pred["evaluated"] is True
        assert pred["predicted"] == {"outcome": "success"}

    @patch("dashboard.routes.tower.spark_engine", new_callable=_mock_spark_engine)
    def test_snapshot_advisories_parsed(self, mock_engine):
        from dashboard.routes.tower import _spark_snapshot

        snap = _spark_snapshot()
        adv = snap["advisories"][0]
        assert adv["category"] == "performance"
        assert adv["priority"] == "high"
        assert adv["title"] == "Slow tasks"
        assert adv["suggested_action"] == "Scale up workers"

    @patch("dashboard.routes.tower.spark_engine")
    def test_snapshot_handles_empty_state(self, mock_engine):
        mock_engine.status.return_value = {"enabled": False}
        mock_engine.get_timeline.return_value = []
        mock_engine.get_predictions.return_value = []
        mock_engine.get_advisories.return_value = []

        from dashboard.routes.tower import _spark_snapshot

        snap = _spark_snapshot()
        assert snap["events"] == []
        assert snap["predictions"] == []
        assert snap["advisories"] == []

    @patch("dashboard.routes.tower.spark_engine")
    def test_snapshot_handles_invalid_json_data(self, mock_engine):
        mock_engine.status.return_value = {"enabled": True}

        event = MagicMock()
        event.event_type = "test"
        event.description = "bad data"
        event.importance = 0.5
        event.created_at = "2026-01-01T00:00:00"
        event.agent_id = None
        event.task_id = None
        event.data = "not-json{"
        mock_engine.get_timeline.return_value = [event]

        pred = MagicMock()
        pred.task_id = None
        pred.accuracy = None
        pred.evaluated_at = None
        pred.created_at = "2026-01-01T00:00:00"
        pred.predicted_value = None
        mock_engine.get_predictions.return_value = [pred]

        mock_engine.get_advisories.return_value = []

        from dashboard.routes.tower import _spark_snapshot

        snap = _spark_snapshot()
        ev = snap["events"][0]
        assert ev["data"] == {}
        assert "agent_id" not in ev
        assert "task_id" not in ev

        pred = snap["predictions"][0]
        assert pred["task_id"] == "?"
        assert pred["predicted"] == {}


class TestTowerWebSocket:
    """Tests for WS /tower/ws endpoint."""

    @patch("dashboard.routes.tower.spark_engine", new_callable=_mock_spark_engine)
    @patch("dashboard.routes.tower._PUSH_INTERVAL", 0)
    def test_ws_sends_initial_snapshot(self, mock_engine, client):
        import json

        with client.websocket_connect("/tower/ws") as ws:
            data = json.loads(ws.receive_text())
            assert data["type"] == "spark_state"
            assert "status" in data
            assert "events" in data
