"""
Tests fuer die Abitur-Docs API

Tests fuer:
- NiBiS Dateinamen-Erkennung
- Dokumenten-Metadaten-Verwaltung
- ZIP-Import
- Status-Workflow
- Enum-Endpunkte
"""

import pytest
from unittest.mock import MagicMock, patch
from datetime import datetime

# Import des zu testenden Moduls
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from abitur_docs_api import (
    router,
    AbiturDokument,
    VerarbeitungsStatus,
    DocumentMetadata,
    RecognitionResult,
    Bundesland,
    AbiturFach,
    Anforderungsniveau,
    DokumentTyp,
    parse_nibis_filename,
    documents_db,
)


class TestNiBiSFilenameRecognition:
    """Tests fuer die automatische NiBiS Dateinamen-Erkennung."""

    def test_parse_deutsch_ea_aufgabe(self):
        """Deutsch eA Aufgabe I sollte erkannt werden."""
        result = parse_nibis_filename("2025_Deutsch_eA_I.pdf")
        assert result.confidence > 0.5
        assert result.extracted.get("jahr") == 2025
        assert result.extracted.get("fach") == "deutsch"
        assert result.extracted.get("niveau") == "eA"
        assert result.extracted.get("aufgaben_nummer") == "I"

    def test_parse_deutsch_ea_ewh(self):
        """Deutsch eA Erwartungshorizont sollte erkannt werden."""
        result = parse_nibis_filename("2025_Deutsch_eA_I_EWH.pdf")
        assert result.confidence > 0.5
        assert result.extracted.get("typ") == "erwartungshorizont"

    def test_parse_englisch_ga(self):
        """Englisch gA sollte erkannt werden."""
        result = parse_nibis_filename("2025_Englisch_gA_II.pdf")
        assert result.extracted.get("fach") == "englisch"
        assert result.extracted.get("niveau") == "gA"
        assert result.extracted.get("aufgaben_nummer") == "II"

    def test_parse_mathematik(self):
        """Mathematik eA sollte erkannt werden."""
        result = parse_nibis_filename("2025_Mathematik_eA_III.pdf")
        assert result.extracted.get("fach") == "mathematik"

    def test_parse_with_hoerverstehen(self):
        """Hoerverstehen sollte erkannt werden."""
        result = parse_nibis_filename("2025_Englisch_eA_Hoerverstehen.pdf")
        assert result.extracted.get("typ") == "hoerverstehen"

    def test_parse_with_sprachmittlung(self):
        """Sprachmittlung sollte erkannt werden."""
        result = parse_nibis_filename("2025_Spanisch_gA_Sprachmittlung.pdf")
        assert result.extracted.get("typ") == "sprachmittlung"

    def test_parse_deckblatt(self):
        """Deckblatt sollte erkannt werden."""
        result = parse_nibis_filename("2025_Geschichte_eA_Deckblatt.pdf")
        assert result.extracted.get("typ") == "deckblatt"

    def test_parse_unknown_format(self):
        """Unbekanntes Format sollte niedrige Confidence haben."""
        result = parse_nibis_filename("random_file.pdf")
        assert result.confidence < 0.3

    def test_parse_year_extraction(self):
        """Jahr sollte aus dem Dateinamen extrahiert werden."""
        result_2024 = parse_nibis_filename("2024_Deutsch_eA_I.pdf")
        result_2025 = parse_nibis_filename("2025_Deutsch_eA_I.pdf")
        assert result_2024.extracted.get("jahr") == 2024
        assert result_2025.extracted.get("jahr") == 2025

    def test_parse_case_insensitive(self):
        """Erkennung sollte case-insensitive sein."""
        result_upper = parse_nibis_filename("2025_DEUTSCH_EA_I.pdf")
        result_lower = parse_nibis_filename("2025_deutsch_ea_i.pdf")
        assert result_upper.extracted.get("fach") == "deutsch"
        assert result_lower.extracted.get("fach") == "deutsch"


class TestVerarbeitungsStatus:
    """Tests fuer den Dokument-Status-Workflow."""

    def test_pending_status(self):
        """Pending Status sollte existieren."""
        assert VerarbeitungsStatus.PENDING.value == "pending"

    def test_recognized_status(self):
        """Recognized Status sollte existieren."""
        assert VerarbeitungsStatus.RECOGNIZED.value == "recognized"

    def test_confirmed_status(self):
        """Confirmed Status sollte existieren."""
        assert VerarbeitungsStatus.CONFIRMED.value == "confirmed"

    def test_indexed_status(self):
        """Indexed Status sollte existieren."""
        assert VerarbeitungsStatus.INDEXED.value == "indexed"

    def test_error_status(self):
        """Error Status sollte existieren."""
        assert VerarbeitungsStatus.ERROR.value == "error"

    def test_status_workflow_order(self):
        """Status-Workflow sollte die richtige Reihenfolge haben."""
        statuses = list(VerarbeitungsStatus)
        expected_order = [
            VerarbeitungsStatus.PENDING,
            VerarbeitungsStatus.PROCESSING,
            VerarbeitungsStatus.RECOGNIZED,
            VerarbeitungsStatus.CONFIRMED,
            VerarbeitungsStatus.INDEXED,
            VerarbeitungsStatus.ERROR,
        ]
        assert statuses == expected_order


class TestBundesland:
    """Tests fuer die Bundesland-Enumeration."""

    def test_niedersachsen(self):
        """Niedersachsen sollte existieren."""
        assert Bundesland.NIEDERSACHSEN.value == "niedersachsen"

    def test_nrw(self):
        """Nordrhein-Westfalen sollte existieren."""
        assert Bundesland.NORDRHEIN_WESTFALEN.value == "nordrhein_westfalen"

    def test_bayern(self):
        """Bayern sollte existieren."""
        assert Bundesland.BAYERN.value == "bayern"

    def test_all_bundeslaender_present(self):
        """Alle wichtigen Bundeslaender sollten vorhanden sein."""
        bundeslaender = [b.value for b in Bundesland]
        assert "niedersachsen" in bundeslaender
        assert "nordrhein_westfalen" in bundeslaender
        assert "bayern" in bundeslaender
        assert "baden_wuerttemberg" in bundeslaender


class TestAbiturFach:
    """Tests fuer die Fach-Enumeration."""

    def test_deutsch(self):
        """Deutsch sollte existieren."""
        assert AbiturFach.DEUTSCH.value == "deutsch"

    def test_mathematik(self):
        """Mathematik sollte existieren."""
        assert AbiturFach.MATHEMATIK.value == "mathematik"

    def test_englisch(self):
        """Englisch sollte existieren."""
        assert AbiturFach.ENGLISCH.value == "englisch"

    def test_sprachen_present(self):
        """Alle Hauptsprachen sollten vorhanden sein."""
        faecher = [f.value for f in AbiturFach]
        assert "deutsch" in faecher
        assert "englisch" in faecher
        assert "franzoesisch" in faecher
        assert "spanisch" in faecher

    def test_naturwissenschaften_present(self):
        """Naturwissenschaften sollten vorhanden sein."""
        faecher = [f.value for f in AbiturFach]
        assert "biologie" in faecher
        assert "chemie" in faecher
        assert "physik" in faecher


class TestAnforderungsniveau:
    """Tests fuer die Anforderungsniveau-Enumeration."""

    def test_ea(self):
        """eA (erhoehtes Anforderungsniveau) sollte existieren."""
        assert Anforderungsniveau.EA.value == "eA"

    def test_ga(self):
        """gA (grundlegendes Anforderungsniveau) sollte existieren."""
        assert Anforderungsniveau.GA.value == "gA"


class TestDokumentTyp:
    """Tests fuer die Dokumenttyp-Enumeration."""

    def test_aufgabe(self):
        """Aufgabe sollte existieren."""
        assert DokumentTyp.AUFGABE.value == "aufgabe"

    def test_erwartungshorizont(self):
        """Erwartungshorizont sollte existieren."""
        assert DokumentTyp.ERWARTUNGSHORIZONT.value == "erwartungshorizont"

    def test_all_types_present(self):
        """Alle Dokumenttypen sollten vorhanden sein."""
        typen = [t.value for t in DokumentTyp]
        assert "aufgabe" in typen
        assert "erwartungshorizont" in typen
        assert "deckblatt" in typen
        assert "hoerverstehen" in typen
        assert "sprachmittlung" in typen


class TestDocumentMetadata:
    """Tests fuer die Dokumenten-Metadaten."""

    def test_create_metadata(self):
        """Metadaten sollten erstellt werden koennen."""
        metadata = DocumentMetadata(
            jahr=2025,
            bundesland="niedersachsen",
            fach="deutsch",
            niveau="eA",
            dokument_typ="aufgabe",
            aufgaben_nummer="I"
        )
        assert metadata.jahr == 2025
        assert metadata.fach == "deutsch"
        assert metadata.niveau == "eA"

    def test_optional_fields(self):
        """Optionale Felder sollten None sein koennen."""
        metadata = DocumentMetadata(
            jahr=None,
            bundesland=None,
            fach=None,
            niveau=None,
            dokument_typ=None,
            aufgaben_nummer=None
        )
        assert metadata.jahr is None
        assert metadata.fach is None


class TestAbiturDokument:
    """Tests fuer das AbiturDokument-Modell."""

    def test_create_document(self):
        """Ein Dokument sollte erstellt werden koennen."""
        # Use internal AbiturDokument dataclass with correct field names
        doc = AbiturDokument(
            id="doc-123",
            dateiname="doc-123.pdf",
            original_dateiname="2025_Deutsch_eA_I.pdf",
            bundesland=Bundesland.NIEDERSACHSEN,
            fach=AbiturFach.DEUTSCH,
            jahr=2025,
            niveau=Anforderungsniveau.EA,
            typ=DokumentTyp.AUFGABE,
            aufgaben_nummer="I",
            status=VerarbeitungsStatus.PENDING,
            confidence=0.85,
            file_path="/data/docs/doc-123.pdf",
            file_size=1024,
            indexed=False,
            vector_ids=[],
            created_at=datetime.now(),
            updated_at=datetime.now()
        )
        assert doc.id == "doc-123"
        assert doc.status == VerarbeitungsStatus.PENDING

    def test_document_with_recognition_result(self):
        """Ein Dokument mit Erkennungsergebnis sollte erstellt werden koennen."""
        # Test that RecognitionResult works with extracted property
        recognition = parse_nibis_filename("2025_Deutsch_eA_I.pdf")
        assert recognition.confidence > 0.5
        assert recognition.extracted.get("fach") == "deutsch"

        doc = AbiturDokument(
            id="doc-456",
            dateiname="doc-456.pdf",
            original_dateiname="2025_Deutsch_eA_I.pdf",
            bundesland=Bundesland.NIEDERSACHSEN,
            fach=AbiturFach.DEUTSCH,
            jahr=2025,
            niveau=Anforderungsniveau.EA,
            typ=DokumentTyp.AUFGABE,
            aufgaben_nummer="I",
            status=VerarbeitungsStatus.RECOGNIZED,
            confidence=recognition.confidence,
            file_path="/data/docs/doc-456.pdf",
            file_size=1024,
            indexed=False,
            vector_ids=[],
            created_at=datetime.now(),
            updated_at=datetime.now()
        )
        assert doc.confidence > 0.5


class TestRecognitionResult:
    """Tests fuer das Erkennungsergebnis."""

    def test_create_recognition_result(self):
        """Ein Erkennungsergebnis sollte erstellt werden koennen."""
        result = parse_nibis_filename("2025_Deutsch_eA_I.pdf")
        assert result.confidence > 0.5
        assert result.method == "filename_pattern"
        assert result.extracted.get("jahr") == 2025
        assert result.extracted.get("fach") == "deutsch"

    def test_confidence_range(self):
        """Confidence sollte zwischen 0 und 1 liegen."""
        result_low = parse_nibis_filename("random_file.pdf")
        result_high = parse_nibis_filename("2025_Deutsch_eA_I_EWH.pdf")
        assert result_low.confidence >= 0.0
        assert result_high.confidence <= 1.0


class TestDocumentsDB:
    """Tests fuer die In-Memory Datenbank."""

    def setup_method(self):
        """Setup vor jedem Test - leere die DB."""
        documents_db.clear()

    def test_empty_db(self):
        """Eine leere DB sollte leer sein."""
        assert len(documents_db) == 0

    def test_add_document_to_db(self):
        """Ein Dokument sollte zur DB hinzugefuegt werden koennen."""
        doc = AbiturDokument(
            id="test-1",
            dateiname="test-1.pdf",
            original_dateiname="test.pdf",
            bundesland=Bundesland.NIEDERSACHSEN,
            fach=AbiturFach.DEUTSCH,
            jahr=2025,
            niveau=Anforderungsniveau.EA,
            typ=DokumentTyp.AUFGABE,
            aufgaben_nummer="I",
            status=VerarbeitungsStatus.PENDING,
            confidence=0.85,
            file_path="/data/test.pdf",
            file_size=1024,
            indexed=False,
            vector_ids=[],
            created_at=datetime.now(),
            updated_at=datetime.now()
        )
        documents_db["test-1"] = doc
        assert "test-1" in documents_db
        assert documents_db["test-1"].original_dateiname == "test.pdf"


class TestFilenamePatterns:
    """Tests fuer verschiedene Dateinamen-Muster."""

    def test_pattern_with_underscore(self):
        """Unterstrich-Trennzeichen sollten erkannt werden."""
        result = parse_nibis_filename("2025_Biologie_eA_II.pdf")
        assert result.extracted.get("fach") == "biologie"

    def test_pattern_with_aufgabe_nummer(self):
        """Roemische Zahlen fuer Aufgaben sollten erkannt werden."""
        for num in ["I", "II", "III", "IV"]:
            result = parse_nibis_filename(f"2025_Deutsch_eA_{num}.pdf")
            assert result.extracted.get("aufgaben_nummer") == num

    def test_pattern_ewh_suffix(self):
        """EWH-Suffix sollte als Erwartungshorizont erkannt werden."""
        result = parse_nibis_filename("2025_Deutsch_eA_I_EWH.pdf")
        assert result.extracted.get("typ") == "erwartungshorizont"

    def test_pattern_without_aufgabe_nummer(self):
        """Dateien ohne Aufgaben-Nummer sollten auch erkannt werden."""
        result = parse_nibis_filename("2025_Deutsch_eA.pdf")
        assert result.extracted.get("jahr") == 2025
        assert result.extracted.get("fach") == "deutsch"


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
