"""
Tests für die Certificates API.

Testet:
- CRUD-Operationen für Zeugnisse
- PDF-Export
- Workflow (Draft -> Review -> Approved -> Issued)
- Notenstatistiken

Note: Some tests require WeasyPrint which needs system libraries.
"""

import pytest
from fastapi.testclient import TestClient
from unittest.mock import patch, AsyncMock
import sys
import os

# Add parent directory to path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

# Check if WeasyPrint is available (required for PDF endpoints)
try:
    import weasyprint
    WEASYPRINT_AVAILABLE = True
except (ImportError, OSError):
    WEASYPRINT_AVAILABLE = False


class TestCertificatesAPIImport:
    """Tests für Certificates API Import."""

    def test_import_certificates_api(self):
        """Test that certificates_api can be imported."""
        from certificates_api import router
        assert router is not None

    def test_import_enums(self):
        """Test that enums can be imported."""
        from certificates_api import CertificateType, CertificateStatus, BehaviorGrade
        assert CertificateType is not None
        assert CertificateStatus is not None
        assert BehaviorGrade is not None

    def test_import_models(self):
        """Test that Pydantic models can be imported."""
        from certificates_api import (
            CertificateCreateRequest,
            CertificateUpdateRequest,
            CertificateResponse,
            SubjectGrade,
            AttendanceInfo
        )
        assert CertificateCreateRequest is not None
        assert SubjectGrade is not None


class TestCertificateTypes:
    """Tests für Zeugnistypen."""

    def test_certificate_types_values(self):
        """Test that all certificate types have correct values."""
        from certificates_api import CertificateType

        expected_types = ["halbjahr", "jahres", "abschluss", "abgang", "uebergang"]
        actual_types = [t.value for t in CertificateType]

        for expected in expected_types:
            assert expected in actual_types

    def test_certificate_status_values(self):
        """Test that all statuses have correct values."""
        from certificates_api import CertificateStatus

        expected_statuses = ["draft", "review", "approved", "issued", "archived"]
        actual_statuses = [s.value for s in CertificateStatus]

        for expected in expected_statuses:
            assert expected in actual_statuses


class TestSubjectGrade:
    """Tests für SubjectGrade Model."""

    def test_create_subject_grade(self):
        """Test creating a subject grade."""
        from certificates_api import SubjectGrade

        grade = SubjectGrade(
            name="Mathematik",
            grade="2",
            points=11,
            note="Gute Mitarbeit"
        )

        assert grade.name == "Mathematik"
        assert grade.grade == "2"
        assert grade.points == 11

    def test_create_subject_grade_minimal(self):
        """Test creating a minimal subject grade."""
        from certificates_api import SubjectGrade

        grade = SubjectGrade(name="Deutsch", grade="1")

        assert grade.name == "Deutsch"
        assert grade.grade == "1"
        assert grade.points is None


class TestAttendanceInfo:
    """Tests für AttendanceInfo Model."""

    def test_create_attendance_info(self):
        """Test creating attendance info."""
        from certificates_api import AttendanceInfo

        attendance = AttendanceInfo(
            days_absent=10,
            days_excused=8,
            days_unexcused=2
        )

        assert attendance.days_absent == 10
        assert attendance.days_excused == 8
        assert attendance.days_unexcused == 2

    def test_default_attendance_values(self):
        """Test default attendance values."""
        from certificates_api import AttendanceInfo

        attendance = AttendanceInfo()

        assert attendance.days_absent == 0
        assert attendance.days_excused == 0
        assert attendance.days_unexcused == 0


class TestCertificateCreateRequest:
    """Tests für CertificateCreateRequest Model."""

    def test_create_certificate_request(self):
        """Test creating a certificate request."""
        from certificates_api import (
            CertificateCreateRequest,
            CertificateType,
            SubjectGrade,
            AttendanceInfo
        )

        request = CertificateCreateRequest(
            student_id="student-123",
            student_name="Max Mustermann",
            student_birthdate="15.05.2010",
            student_class="5a",
            school_year="2024/2025",
            certificate_type=CertificateType.HALBJAHR,
            subjects=[
                SubjectGrade(name="Deutsch", grade="2"),
                SubjectGrade(name="Mathematik", grade="2"),
            ],
            attendance=AttendanceInfo(days_absent=5, days_excused=5),
            class_teacher="Frau Schmidt",
            principal="Herr Direktor"
        )

        assert request.student_name == "Max Mustermann"
        assert request.certificate_type == CertificateType.HALBJAHR
        assert len(request.subjects) == 2


class TestHelperFunctions:
    """Tests für Helper-Funktionen."""

    def test_calculate_average(self):
        """Test average calculation."""
        from certificates_api import _calculate_average

        subjects = [
            {"name": "Deutsch", "grade": "2"},
            {"name": "Mathe", "grade": "3"},
            {"name": "Englisch", "grade": "1"}
        ]

        avg = _calculate_average(subjects)
        assert avg == 2.0

    def test_calculate_average_empty(self):
        """Test average calculation with empty list."""
        from certificates_api import _calculate_average

        avg = _calculate_average([])
        assert avg is None

    def test_calculate_average_non_numeric(self):
        """Test average calculation with non-numeric grades."""
        from certificates_api import _calculate_average

        subjects = [
            {"name": "Deutsch", "grade": "A"},
            {"name": "Mathe", "grade": "B"}
        ]

        avg = _calculate_average(subjects)
        assert avg is None

    def test_get_type_label(self):
        """Test type label function."""
        from certificates_api import _get_type_label, CertificateType

        assert "Halbjahres" in _get_type_label(CertificateType.HALBJAHR)
        assert "Jahres" in _get_type_label(CertificateType.JAHRES)
        assert "Abschluss" in _get_type_label(CertificateType.ABSCHLUSS)


@pytest.mark.skipif(
    not WEASYPRINT_AVAILABLE,
    reason="WeasyPrint not available (requires system libraries)"
)
class TestCertificatesAPIEndpoints:
    """Integration tests für Certificates API Endpoints."""

    @pytest.fixture
    def client(self):
        """Create test client."""
        try:
            from main import app
            return TestClient(app)
        except ImportError:
            pytest.skip("main.py not available for testing")

    @pytest.fixture
    def sample_certificate_data(self):
        """Sample certificate data for tests."""
        return {
            "student_id": "student-test-123",
            "student_name": "Test Schüler",
            "student_birthdate": "01.01.2012",
            "student_class": "5a",
            "school_year": "2024/2025",
            "certificate_type": "halbjahr",
            "subjects": [
                {"name": "Deutsch", "grade": "2"},
                {"name": "Mathematik", "grade": "3"},
                {"name": "Englisch", "grade": "2"}
            ],
            "attendance": {
                "days_absent": 5,
                "days_excused": 4,
                "days_unexcused": 1
            },
            "class_teacher": "Frau Test",
            "principal": "Herr Direktor"
        }

    def test_create_certificate(self, client, sample_certificate_data):
        """Test creating a new certificate."""
        if not client:
            pytest.skip("Client not available")

        response = client.post("/api/certificates/", json=sample_certificate_data)

        assert response.status_code == 200
        data = response.json()
        assert data["student_name"] == sample_certificate_data["student_name"]
        assert data["status"] == "draft"
        assert "id" in data
        assert data["average_grade"] is not None

    def test_get_certificate(self, client, sample_certificate_data):
        """Test getting a certificate by ID."""
        if not client:
            pytest.skip("Client not available")

        # First create a certificate
        create_response = client.post("/api/certificates/", json=sample_certificate_data)
        cert_id = create_response.json()["id"]

        # Then get it
        response = client.get(f"/api/certificates/{cert_id}")

        assert response.status_code == 200
        data = response.json()
        assert data["id"] == cert_id

    def test_update_certificate(self, client, sample_certificate_data):
        """Test updating a certificate."""
        if not client:
            pytest.skip("Client not available")

        # Create certificate
        create_response = client.post("/api/certificates/", json=sample_certificate_data)
        cert_id = create_response.json()["id"]

        # Update it
        update_data = {"remarks": "Versetzung in Klasse 6a"}
        response = client.put(f"/api/certificates/{cert_id}", json=update_data)

        assert response.status_code == 200
        data = response.json()
        assert data["remarks"] == "Versetzung in Klasse 6a"

    def test_delete_certificate(self, client, sample_certificate_data):
        """Test deleting a certificate."""
        if not client:
            pytest.skip("Client not available")

        # Create certificate
        create_response = client.post("/api/certificates/", json=sample_certificate_data)
        cert_id = create_response.json()["id"]

        # Delete it
        response = client.delete(f"/api/certificates/{cert_id}")
        assert response.status_code == 200

        # Verify it's deleted
        get_response = client.get(f"/api/certificates/{cert_id}")
        assert get_response.status_code == 404

    def test_export_pdf(self, client, sample_certificate_data):
        """Test PDF export."""
        if not client:
            pytest.skip("Client not available")

        # Create certificate
        create_response = client.post("/api/certificates/", json=sample_certificate_data)
        cert_id = create_response.json()["id"]

        # Export as PDF
        response = client.post(f"/api/certificates/{cert_id}/export-pdf")

        assert response.status_code == 200
        assert response.headers["content-type"] == "application/pdf"
        assert b"%PDF" in response.content[:10]

    def test_certificate_workflow(self, client, sample_certificate_data):
        """Test complete certificate workflow."""
        if not client:
            pytest.skip("Client not available")

        # 1. Create (draft)
        create_response = client.post("/api/certificates/", json=sample_certificate_data)
        cert_id = create_response.json()["id"]
        assert create_response.json()["status"] == "draft"

        # 2. Submit for review
        review_response = client.post(f"/api/certificates/{cert_id}/submit-review")
        assert review_response.status_code == 200
        assert review_response.json()["status"] == "review"

        # 3. Approve
        approve_response = client.post(f"/api/certificates/{cert_id}/approve")
        assert approve_response.status_code == 200
        assert approve_response.json()["status"] == "approved"

        # 4. Issue
        issue_response = client.post(f"/api/certificates/{cert_id}/issue")
        assert issue_response.status_code == 200
        assert issue_response.json()["status"] == "issued"

        # 5. Cannot update after issued
        update_response = client.put(f"/api/certificates/{cert_id}", json={"remarks": "Test"})
        assert update_response.status_code == 400

    def test_get_certificate_types(self, client):
        """Test getting available certificate types."""
        if not client:
            pytest.skip("Client not available")

        response = client.get("/api/certificates/types")

        assert response.status_code == 200
        data = response.json()
        assert "types" in data
        assert len(data["types"]) >= 5

    def test_get_behavior_grades(self, client):
        """Test getting available behavior grades."""
        if not client:
            pytest.skip("Client not available")

        response = client.get("/api/certificates/behavior-grades")

        assert response.status_code == 200
        data = response.json()
        assert "grades" in data
        assert len(data["grades"]) == 4

    def test_get_nonexistent_certificate(self, client):
        """Test getting a certificate that doesn't exist."""
        if not client:
            pytest.skip("Client not available")

        response = client.get("/api/certificates/nonexistent-id")
        assert response.status_code == 404


# Run tests if executed directly
if __name__ == "__main__":
    pytest.main([__file__, "-v"])
