"""
Tests für Alerts Agent API Routes.

Testet alle Endpoints: ingest, run, inbox, feedback, profile, stats.
"""

import pytest
from datetime import datetime
from fastapi import FastAPI
from fastapi.testclient import TestClient

from alerts_agent.api.routes import router, _alerts_store, _profile_store
from alerts_agent.models.alert_item import AlertStatus


# Test App erstellen
app = FastAPI()
app.include_router(router, prefix="/api")


class TestIngestEndpoint:
    """Tests für POST /alerts/ingest."""

    def setup_method(self):
        """Setup für jeden Test."""
        _alerts_store.clear()
        _profile_store.clear()
        self.client = TestClient(app)

    def test_ingest_minimal(self):
        """Test minimaler Alert-Import."""
        response = self.client.post(
            "/api/alerts/ingest",
            json={
                "title": "Test Alert",
                "url": "https://example.com/test",
            },
        )

        assert response.status_code == 200
        data = response.json()
        assert data["status"] == "created"
        assert "id" in data
        assert len(data["id"]) == 36  # UUID

    def test_ingest_full(self):
        """Test vollständiger Alert-Import."""
        response = self.client.post(
            "/api/alerts/ingest",
            json={
                "title": "Neue Inklusions-Richtlinie",
                "url": "https://example.com/inklusion",
                "snippet": "Das Kultusministerium hat neue Richtlinien...",
                "topic_label": "Inklusion Bayern",
                "published_at": "2024-01-15T10:30:00",
            },
        )

        assert response.status_code == 200
        data = response.json()
        assert "Inklusions-Richtlinie" in data["message"]

    def test_ingest_stores_alert(self):
        """Test dass Alert gespeichert wird."""
        response = self.client.post(
            "/api/alerts/ingest",
            json={
                "title": "Stored Alert",
                "url": "https://example.com/stored",
            },
        )

        alert_id = response.json()["id"]
        assert alert_id in _alerts_store
        assert _alerts_store[alert_id].title == "Stored Alert"

    def test_ingest_validation_missing_title(self):
        """Test Validierung: Titel fehlt."""
        response = self.client.post(
            "/api/alerts/ingest",
            json={
                "url": "https://example.com/test",
            },
        )
        assert response.status_code == 422

    def test_ingest_validation_missing_url(self):
        """Test Validierung: URL fehlt."""
        response = self.client.post(
            "/api/alerts/ingest",
            json={
                "title": "Test",
            },
        )
        assert response.status_code == 422

    def test_ingest_validation_empty_title(self):
        """Test Validierung: Leerer Titel."""
        response = self.client.post(
            "/api/alerts/ingest",
            json={
                "title": "",
                "url": "https://example.com",
            },
        )
        assert response.status_code == 422


class TestRunEndpoint:
    """Tests für POST /alerts/run."""

    def setup_method(self):
        """Setup für jeden Test."""
        _alerts_store.clear()
        _profile_store.clear()
        self.client = TestClient(app)

    def test_run_empty(self):
        """Test Scoring ohne Alerts."""
        response = self.client.post(
            "/api/alerts/run",
            json={"limit": 10},
        )

        assert response.status_code == 200
        data = response.json()
        assert data["processed"] == 0
        assert data["keep"] == 0
        assert data["drop"] == 0

    def test_run_scores_alerts(self):
        """Test Scoring bewertet Alerts."""
        # Alerts importieren
        self.client.post("/api/alerts/ingest", json={
            "title": "Inklusion in Schulen",
            "url": "https://example.com/1",
        })
        self.client.post("/api/alerts/ingest", json={
            "title": "Stellenanzeige Lehrer",
            "url": "https://example.com/2",
        })

        # Scoring starten
        response = self.client.post(
            "/api/alerts/run",
            json={"limit": 10},
        )

        assert response.status_code == 200
        data = response.json()
        assert data["processed"] == 2
        assert data["keep"] + data["drop"] + data["review"] == 2

    def test_run_keyword_scoring_keep(self):
        """Test Keyword-Scoring: Priorität → KEEP."""
        # Explizit "Datenschutz Schule" als Snippet für besseren Match
        self.client.post("/api/alerts/ingest", json={
            "title": "Neue Datenschutz-Regelung für Schulen",
            "url": "https://example.com/datenschutz",
            "snippet": "Datenschutz Schule DSGVO Regelung",
        })

        response = self.client.post("/api/alerts/run", json={"limit": 10})
        data = response.json()

        # Sollte als KEEP oder REVIEW bewertet werden (nicht DROP)
        assert data["drop"] == 0
        assert data["keep"] + data["review"] == 1

    def test_run_keyword_scoring_drop(self):
        """Test Keyword-Scoring: Ausschluss → DROP."""
        self.client.post("/api/alerts/ingest", json={
            "title": "Stellenanzeige: Schulleiter gesucht",
            "url": "https://example.com/job",
        })

        response = self.client.post("/api/alerts/run", json={"limit": 10})
        data = response.json()

        assert data["drop"] == 1
        assert data["keep"] == 0

    def test_run_skip_scored(self):
        """Test bereits bewertete werden übersprungen."""
        self.client.post("/api/alerts/ingest", json={
            "title": "Test Alert",
            "url": "https://example.com/test",
        })

        # Erstes Scoring
        self.client.post("/api/alerts/run", json={"limit": 10})

        # Zweites Scoring mit skip_scored=true
        response = self.client.post(
            "/api/alerts/run",
            json={"limit": 10, "skip_scored": True},
        )
        data = response.json()

        assert data["processed"] == 0

    def test_run_rescore(self):
        """Test Re-Scoring mit skip_scored=false."""
        self.client.post("/api/alerts/ingest", json={
            "title": "Test Alert",
            "url": "https://example.com/test",
        })

        # Erstes Scoring
        self.client.post("/api/alerts/run", json={"limit": 10})

        # Zweites Scoring mit skip_scored=false
        response = self.client.post(
            "/api/alerts/run",
            json={"limit": 10, "skip_scored": False},
        )
        data = response.json()

        assert data["processed"] == 1

    def test_run_limit(self):
        """Test Limit Parameter."""
        # 5 Alerts importieren
        for i in range(5):
            self.client.post("/api/alerts/ingest", json={
                "title": f"Alert {i}",
                "url": f"https://example.com/{i}",
            })

        # Nur 2 scoren
        response = self.client.post(
            "/api/alerts/run",
            json={"limit": 2},
        )
        data = response.json()

        assert data["processed"] == 2

    def test_run_returns_duration(self):
        """Test Duration wird zurückgegeben."""
        response = self.client.post("/api/alerts/run", json={"limit": 10})
        data = response.json()

        assert "duration_ms" in data
        assert isinstance(data["duration_ms"], int)


class TestInboxEndpoint:
    """Tests für GET /alerts/inbox."""

    def setup_method(self):
        """Setup für jeden Test."""
        _alerts_store.clear()
        _profile_store.clear()
        self.client = TestClient(app)

    def _create_and_score_alerts(self):
        """Helfer: Erstelle und score Test-Alerts."""
        # KEEP Alert
        self.client.post("/api/alerts/ingest", json={
            "title": "Inklusion Regelung",
            "url": "https://example.com/keep",
        })
        # DROP Alert
        self.client.post("/api/alerts/ingest", json={
            "title": "Stellenanzeige",
            "url": "https://example.com/drop",
        })
        # Scoring
        self.client.post("/api/alerts/run", json={"limit": 10})

    def test_inbox_empty(self):
        """Test leere Inbox."""
        response = self.client.get("/api/alerts/inbox")

        assert response.status_code == 200
        data = response.json()
        assert data["items"] == []
        assert data["total"] == 0

    def test_inbox_shows_keep_and_review(self):
        """Test Inbox zeigt KEEP und REVIEW."""
        self._create_and_score_alerts()

        response = self.client.get("/api/alerts/inbox")
        data = response.json()

        # Nur KEEP sollte angezeigt werden (Stellenanzeige ist DROP)
        assert data["total"] == 1
        assert data["items"][0]["relevance_decision"] == "KEEP"

    def test_inbox_filter_by_decision(self):
        """Test Inbox Filter nach Decision."""
        self._create_and_score_alerts()

        # Nur DROP
        response = self.client.get("/api/alerts/inbox?decision=DROP")
        data = response.json()

        assert data["total"] == 1
        assert data["items"][0]["relevance_decision"] == "DROP"

    def test_inbox_pagination(self):
        """Test Inbox Pagination."""
        # 5 KEEP Alerts
        for i in range(5):
            self.client.post("/api/alerts/ingest", json={
                "title": f"Inklusion Alert {i}",
                "url": f"https://example.com/{i}",
            })
        self.client.post("/api/alerts/run", json={"limit": 10})

        # Erste Seite
        response = self.client.get("/api/alerts/inbox?page=1&page_size=2")
        data = response.json()

        assert data["total"] == 5
        assert len(data["items"]) == 2
        assert data["page"] == 1
        assert data["page_size"] == 2

        # Zweite Seite
        response = self.client.get("/api/alerts/inbox?page=2&page_size=2")
        data = response.json()

        assert len(data["items"]) == 2

    def test_inbox_item_fields(self):
        """Test Inbox Items haben alle Felder."""
        self.client.post("/api/alerts/ingest", json={
            "title": "Test Alert",
            "url": "https://example.com/test",
            "snippet": "Test snippet",
            "topic_label": "Test Topic",
        })
        self.client.post("/api/alerts/run", json={"limit": 10})

        response = self.client.get("/api/alerts/inbox?decision=REVIEW")
        data = response.json()

        if data["items"]:
            item = data["items"][0]
            assert "id" in item
            assert "title" in item
            assert "url" in item
            assert "snippet" in item
            assert "topic_label" in item
            assert "relevance_score" in item
            assert "relevance_decision" in item
            assert "status" in item


class TestFeedbackEndpoint:
    """Tests für POST /alerts/feedback."""

    def setup_method(self):
        """Setup für jeden Test."""
        _alerts_store.clear()
        _profile_store.clear()
        self.client = TestClient(app)

    def _create_alert(self):
        """Helfer: Erstelle Test-Alert."""
        response = self.client.post("/api/alerts/ingest", json={
            "title": "Test Alert",
            "url": "https://example.com/test",
        })
        return response.json()["id"]

    def test_feedback_positive(self):
        """Test positives Feedback."""
        alert_id = self._create_alert()

        response = self.client.post(
            "/api/alerts/feedback",
            json={
                "alert_id": alert_id,
                "is_relevant": True,
                "reason": "Sehr relevant",
            },
        )

        assert response.status_code == 200
        data = response.json()
        assert data["success"] is True
        assert data["profile_updated"] is True

    def test_feedback_negative(self):
        """Test negatives Feedback."""
        alert_id = self._create_alert()

        response = self.client.post(
            "/api/alerts/feedback",
            json={
                "alert_id": alert_id,
                "is_relevant": False,
                "reason": "Werbung",
            },
        )

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

    def test_feedback_updates_alert_status(self):
        """Test Feedback aktualisiert Alert-Status."""
        alert_id = self._create_alert()

        self.client.post("/api/alerts/feedback", json={
            "alert_id": alert_id,
            "is_relevant": True,
        })

        assert _alerts_store[alert_id].status == AlertStatus.REVIEWED

    def test_feedback_updates_profile(self):
        """Test Feedback aktualisiert Profil."""
        alert_id = self._create_alert()

        # Positives Feedback
        self.client.post("/api/alerts/feedback", json={
            "alert_id": alert_id,
            "is_relevant": True,
            "reason": "Wichtig",
        })

        profile = _profile_store.get("default")
        assert profile is not None
        assert profile.total_kept == 1
        assert len(profile.positive_examples) == 1

    def test_feedback_not_found(self):
        """Test Feedback für nicht existierenden Alert."""
        response = self.client.post(
            "/api/alerts/feedback",
            json={
                "alert_id": "non-existent-id",
                "is_relevant": True,
            },
        )

        assert response.status_code == 404

    def test_feedback_with_tags(self):
        """Test Feedback mit Tags."""
        alert_id = self._create_alert()

        response = self.client.post(
            "/api/alerts/feedback",
            json={
                "alert_id": alert_id,
                "is_relevant": True,
                "tags": ["wichtig", "inklusion"],
            },
        )

        assert response.status_code == 200


class TestProfileEndpoint:
    """Tests für GET/PUT /alerts/profile."""

    def setup_method(self):
        """Setup für jeden Test."""
        _alerts_store.clear()
        _profile_store.clear()
        self.client = TestClient(app)

    def test_get_profile_default(self):
        """Test Default-Profil abrufen."""
        response = self.client.get("/api/alerts/profile")

        assert response.status_code == 200
        data = response.json()
        assert "id" in data
        assert "priorities" in data
        assert "exclusions" in data
        assert len(data["priorities"]) > 0  # Default hat Prioritäten

    def test_get_profile_creates_default(self):
        """Test Profil wird automatisch erstellt."""
        assert "default" not in _profile_store

        self.client.get("/api/alerts/profile")

        assert "default" in _profile_store

    def test_update_profile_priorities(self):
        """Test Prioritäten aktualisieren."""
        response = self.client.put(
            "/api/alerts/profile",
            json={
                "priorities": [
                    {"label": "Neue Priorität", "weight": 0.9},
                    {"label": "Zweite Priorität", "weight": 0.7},
                ],
            },
        )

        assert response.status_code == 200
        data = response.json()
        assert len(data["priorities"]) == 2
        assert data["priorities"][0]["label"] == "Neue Priorität"

    def test_update_profile_exclusions(self):
        """Test Ausschlüsse aktualisieren."""
        response = self.client.put(
            "/api/alerts/profile",
            json={
                "exclusions": ["Spam", "Werbung", "Newsletter"],
            },
        )

        assert response.status_code == 200
        data = response.json()
        assert "Spam" in data["exclusions"]
        assert len(data["exclusions"]) == 3

    def test_update_profile_policies(self):
        """Test Policies aktualisieren."""
        response = self.client.put(
            "/api/alerts/profile",
            json={
                "policies": {
                    "max_age_days": 14,
                    "prefer_german_sources": True,
                },
            },
        )

        assert response.status_code == 200
        data = response.json()
        assert data["policies"]["max_age_days"] == 14

    def test_profile_stats(self):
        """Test Profil enthält Statistiken."""
        response = self.client.get("/api/alerts/profile")
        data = response.json()

        assert "total_scored" in data
        assert "total_kept" in data
        assert "total_dropped" in data


class TestStatsEndpoint:
    """Tests für GET /alerts/stats."""

    def setup_method(self):
        """Setup für jeden Test."""
        _alerts_store.clear()
        _profile_store.clear()
        self.client = TestClient(app)

    def test_stats_empty(self):
        """Test Stats ohne Alerts."""
        response = self.client.get("/api/alerts/stats")

        assert response.status_code == 200
        data = response.json()
        assert data["total_alerts"] == 0

    def test_stats_with_alerts(self):
        """Test Stats mit Alerts."""
        # Alerts erstellen und scoren
        self.client.post("/api/alerts/ingest", json={
            "title": "Inklusion",
            "url": "https://example.com/1",
        })
        self.client.post("/api/alerts/ingest", json={
            "title": "Stellenanzeige",
            "url": "https://example.com/2",
        })
        self.client.post("/api/alerts/run", json={"limit": 10})

        response = self.client.get("/api/alerts/stats")
        data = response.json()

        assert data["total_alerts"] == 2
        assert "by_status" in data
        assert "by_decision" in data
        assert "scored" in data["by_status"]

    def test_stats_avg_score(self):
        """Test Durchschnittlicher Score."""
        self.client.post("/api/alerts/ingest", json={
            "title": "Test",
            "url": "https://example.com/1",
        })
        self.client.post("/api/alerts/run", json={"limit": 10})

        response = self.client.get("/api/alerts/stats")
        data = response.json()

        assert "avg_score" in data
        assert data["avg_score"] is not None
