"""
School Resolver Service - Schul-Auswahl und Klassen-Erstellung.

Funktionen:
- Bundesland -> Schulform -> Schule Kaskade
- Auto-Erstellung von Klassen aus erkannten Daten
- Integration mit Go School Service (Port 8084)

Privacy:
- Schuldaten sind Stammdaten (kein DSGVO-Problem)
- Schueler-Erstellung nur im Lehrer-Namespace
"""

import httpx
import os
from dataclasses import dataclass, field
from typing import List, Optional, Dict, Any
from enum import Enum


# ============================================================================
# KONSTANTEN
# ============================================================================

BUNDESLAENDER = {
    "BW": "Baden-Wuerttemberg",
    "BY": "Bayern",
    "BE": "Berlin",
    "BB": "Brandenburg",
    "HB": "Bremen",
    "HH": "Hamburg",
    "HE": "Hessen",
    "MV": "Mecklenburg-Vorpommern",
    "NI": "Niedersachsen",
    "NW": "Nordrhein-Westfalen",
    "RP": "Rheinland-Pfalz",
    "SL": "Saarland",
    "SN": "Sachsen",
    "ST": "Sachsen-Anhalt",
    "SH": "Schleswig-Holstein",
    "TH": "Thueringen"
}

SCHULFORMEN = {
    "grundschule": {
        "name": "Grundschule",
        "grades": [1, 2, 3, 4],
        "short": "GS"
    },
    "hauptschule": {
        "name": "Hauptschule",
        "grades": [5, 6, 7, 8, 9, 10],
        "short": "HS"
    },
    "realschule": {
        "name": "Realschule",
        "grades": [5, 6, 7, 8, 9, 10],
        "short": "RS"
    },
    "gymnasium": {
        "name": "Gymnasium",
        "grades": [5, 6, 7, 8, 9, 10, 11, 12, 13],
        "short": "GYM"
    },
    "gesamtschule": {
        "name": "Gesamtschule",
        "grades": [5, 6, 7, 8, 9, 10, 11, 12, 13],
        "short": "IGS"
    },
    "oberschule": {
        "name": "Oberschule",
        "grades": [5, 6, 7, 8, 9, 10],
        "short": "OBS"
    },
    "sekundarschule": {
        "name": "Sekundarschule",
        "grades": [5, 6, 7, 8, 9, 10],
        "short": "SEK"
    },
    "foerderschule": {
        "name": "Foerderschule",
        "grades": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
        "short": "FS"
    },
    "berufsschule": {
        "name": "Berufsschule",
        "grades": [10, 11, 12, 13],
        "short": "BS"
    },
    "fachoberschule": {
        "name": "Fachoberschule",
        "grades": [11, 12, 13],
        "short": "FOS"
    }
}

# Faecher mit Standardbezeichnungen
FAECHER = {
    "mathematik": {"name": "Mathematik", "short": "Ma"},
    "deutsch": {"name": "Deutsch", "short": "De"},
    "englisch": {"name": "Englisch", "short": "En"},
    "franzoesisch": {"name": "Franzoesisch", "short": "Fr"},
    "spanisch": {"name": "Spanisch", "short": "Sp"},
    "latein": {"name": "Latein", "short": "La"},
    "physik": {"name": "Physik", "short": "Ph"},
    "chemie": {"name": "Chemie", "short": "Ch"},
    "biologie": {"name": "Biologie", "short": "Bio"},
    "geschichte": {"name": "Geschichte", "short": "Ge"},
    "erdkunde": {"name": "Erdkunde", "short": "Ek"},
    "politik": {"name": "Politik", "short": "Po"},
    "wirtschaft": {"name": "Wirtschaft", "short": "Wi"},
    "kunst": {"name": "Kunst", "short": "Ku"},
    "musik": {"name": "Musik", "short": "Mu"},
    "sport": {"name": "Sport", "short": "Sp"},
    "religion": {"name": "Religion", "short": "Re"},
    "ethik": {"name": "Ethik", "short": "Et"},
    "informatik": {"name": "Informatik", "short": "If"},
    "sachunterricht": {"name": "Sachunterricht", "short": "SU"}
}


# ============================================================================
# DATA CLASSES
# ============================================================================

@dataclass
class School:
    """Schule."""
    id: str
    name: str
    bundesland: str
    schulform: str
    address: Optional[str] = None
    city: Optional[str] = None


@dataclass
class SchoolClass:
    """Schulklasse."""
    id: str
    school_id: str
    name: str  # z.B. "3a"
    grade_level: int  # z.B. 3
    school_year: str  # z.B. "2025/2026"
    teacher_id: str
    student_count: int = 0


@dataclass
class Student:
    """Schueler (Stammdaten, keine PII im Klausur-Kontext)."""
    id: str
    class_id: str
    first_name: str
    last_name: str
    student_number: Optional[str] = None


@dataclass
class DetectedClassInfo:
    """Aus Klausuren erkannte Klasseninformationen."""
    class_name: str  # z.B. "3a"
    grade_level: Optional[int] = None  # z.B. 3
    subject: Optional[str] = None
    date: Optional[str] = None
    students: List[Dict[str, str]] = field(default_factory=list)
    confidence: float = 0.0


@dataclass
class SchoolContext:
    """Vollstaendiger Schulkontext fuer einen Lehrer."""
    teacher_id: str
    school: Optional[School] = None
    classes: List[SchoolClass] = field(default_factory=list)
    current_school_year: str = "2025/2026"


# ============================================================================
# SCHOOL RESOLVER
# ============================================================================

class SchoolResolver:
    """
    Verwaltet Schul- und Klassenkontext.

    Beispiel:
        resolver = SchoolResolver()

        # Schul-Kaskade
        schools = await resolver.search_schools("Niedersachsen", "Grundschule", "Jever")

        # Klasse auto-erstellen
        class_obj = await resolver.auto_create_class(
            teacher_id="teacher-123",
            school_id="school-456",
            detected_info=DetectedClassInfo(
                class_name="3a",
                students=[{"firstName": "Max"}, {"firstName": "Anna"}]
            )
        )
    """

    def __init__(self):
        self.school_service_url = os.getenv(
            "SCHOOL_SERVICE_URL",
            "http://school-service:8084"
        )
        # Fallback auf lokale Daten wenn Service nicht erreichbar
        self._local_schools: Dict[str, School] = {}
        self._local_classes: Dict[str, SchoolClass] = {}

    # =========================================================================
    # BUNDESLAND / SCHULFORM LOOKUP
    # =========================================================================

    def get_bundeslaender(self) -> Dict[str, str]:
        """Gibt alle Bundeslaender zurueck."""
        return BUNDESLAENDER

    def get_schulformen(self) -> Dict[str, Dict]:
        """Gibt alle Schulformen zurueck."""
        return SCHULFORMEN

    def get_faecher(self) -> Dict[str, Dict]:
        """Gibt alle Faecher zurueck."""
        return FAECHER

    def get_grades_for_schulform(self, schulform: str) -> List[int]:
        """Gibt die Klassenstufen fuer eine Schulform zurueck."""
        if schulform in SCHULFORMEN:
            return SCHULFORMEN[schulform]["grades"]
        return list(range(1, 14))  # Default: alle Stufen

    def detect_grade_from_class_name(self, class_name: str) -> Optional[int]:
        """
        Erkennt die Klassenstufe aus dem Klassennamen.

        Beispiele:
        - "3a" -> 3
        - "10b" -> 10
        - "Q1" -> 11
        - "EF" -> 10
        """
        import re

        # Standard-Format: Zahl + Buchstabe
        match = re.match(r'^(\d{1,2})[a-zA-Z]?$', class_name)
        if match:
            return int(match.group(1))

        # Oberstufen-Formate
        upper_grades = {
            'ef': 10, 'e': 10,
            'q1': 11, 'q2': 12,
            'k1': 11, 'k2': 12,
            '11': 11, '12': 12, '13': 13
        }

        class_lower = class_name.lower()
        if class_lower in upper_grades:
            return upper_grades[class_lower]

        return None

    def normalize_subject(self, detected_subject: str) -> Optional[str]:
        """
        Normalisiert einen erkannten Fachnamen.

        Beispiel: "Mathe" -> "mathematik"
        """
        subject_lower = detected_subject.lower().strip()

        # Direkte Matches
        if subject_lower in FAECHER:
            return subject_lower

        # Abkuerzungen und Varianten
        subject_aliases = {
            'mathe': 'mathematik',
            'bio': 'biologie',
            'phy': 'physik',
            'che': 'chemie',
            'geo': 'erdkunde',
            'geographie': 'erdkunde',
            'powi': 'politik',
            'sowi': 'politik',
            'reli': 'religion',
            'info': 'informatik',
            'su': 'sachunterricht'
        }

        if subject_lower in subject_aliases:
            return subject_aliases[subject_lower]

        # Teilstring-Match
        for key in FAECHER:
            if key.startswith(subject_lower) or subject_lower.startswith(key[:3]):
                return key

        return None

    # =========================================================================
    # SCHOOL SERVICE INTEGRATION
    # =========================================================================

    async def search_schools(
        self,
        bundesland: Optional[str] = None,
        schulform: Optional[str] = None,
        name_query: Optional[str] = None,
        limit: int = 20
    ) -> List[School]:
        """
        Sucht Schulen im School Service.

        Args:
            bundesland: Bundesland-Kuerzel (z.B. "NI")
            schulform: Schulform-Key (z.B. "grundschule")
            name_query: Suchbegriff fuer Schulname
            limit: Max. Anzahl Ergebnisse
        """
        try:
            async with httpx.AsyncClient(timeout=10.0) as client:
                params = {}
                if bundesland:
                    params['state'] = bundesland
                if schulform:
                    params['type'] = schulform
                if name_query:
                    params['q'] = name_query
                params['limit'] = limit

                response = await client.get(
                    f"{self.school_service_url}/api/schools",
                    params=params
                )

                if response.status_code == 200:
                    data = response.json()
                    return [
                        School(
                            id=s['id'],
                            name=s['name'],
                            bundesland=s.get('state', bundesland or ''),
                            schulform=s.get('type', schulform or ''),
                            address=s.get('address'),
                            city=s.get('city')
                        )
                        for s in data.get('schools', [])
                    ]

        except Exception as e:
            print(f"[SchoolResolver] Service error: {e}")

        # Fallback: Leere Liste (Schule kann manuell angelegt werden)
        return []

    async def get_or_create_school(
        self,
        teacher_id: str,
        bundesland: str,
        schulform: str,
        school_name: str,
        city: Optional[str] = None
    ) -> School:
        """
        Holt oder erstellt eine Schule.

        Falls die Schule existiert, wird sie zurueckgegeben.
        Sonst wird sie neu erstellt.
        """
        # Zuerst suchen
        existing = await self.search_schools(
            bundesland=bundesland,
            schulform=schulform,
            name_query=school_name,
            limit=1
        )

        if existing:
            return existing[0]

        # Neu erstellen
        try:
            async with httpx.AsyncClient(timeout=10.0) as client:
                response = await client.post(
                    f"{self.school_service_url}/api/schools",
                    json={
                        "name": school_name,
                        "state": bundesland,
                        "type": schulform,
                        "city": city,
                        "created_by": teacher_id
                    }
                )

                if response.status_code in (200, 201):
                    data = response.json()
                    return School(
                        id=data['id'],
                        name=school_name,
                        bundesland=bundesland,
                        schulform=schulform,
                        city=city
                    )

        except Exception as e:
            print(f"[SchoolResolver] Create school error: {e}")

        # Fallback: Lokale Schule erstellen
        import uuid
        school_id = str(uuid.uuid4())
        school = School(
            id=school_id,
            name=school_name,
            bundesland=bundesland,
            schulform=schulform,
            city=city
        )
        self._local_schools[school_id] = school
        return school

    # =========================================================================
    # CLASS MANAGEMENT
    # =========================================================================

    async def get_classes_for_teacher(
        self,
        teacher_id: str,
        school_id: Optional[str] = None
    ) -> List[SchoolClass]:
        """Holt alle Klassen eines Lehrers."""
        try:
            async with httpx.AsyncClient(timeout=10.0) as client:
                params = {"teacher_id": teacher_id}
                if school_id:
                    params["school_id"] = school_id

                response = await client.get(
                    f"{self.school_service_url}/api/classes",
                    params=params
                )

                if response.status_code == 200:
                    data = response.json()
                    return [
                        SchoolClass(
                            id=c['id'],
                            school_id=c.get('school_id', ''),
                            name=c['name'],
                            grade_level=c.get('grade_level', 0),
                            school_year=c.get('school_year', '2025/2026'),
                            teacher_id=teacher_id,
                            student_count=c.get('student_count', 0)
                        )
                        for c in data.get('classes', [])
                    ]

        except Exception as e:
            print(f"[SchoolResolver] Get classes error: {e}")

        return list(self._local_classes.values())

    async def auto_create_class(
        self,
        teacher_id: str,
        school_id: str,
        detected_info: DetectedClassInfo,
        school_year: str = "2025/2026"
    ) -> SchoolClass:
        """
        Erstellt automatisch eine Klasse aus erkannten Daten.

        Args:
            teacher_id: ID des Lehrers
            school_id: ID der Schule
            detected_info: Aus Klausuren erkannte Informationen
            school_year: Schuljahr
        """
        grade_level = detected_info.grade_level or self.detect_grade_from_class_name(
            detected_info.class_name
        ) or 0

        try:
            async with httpx.AsyncClient(timeout=10.0) as client:
                response = await client.post(
                    f"{self.school_service_url}/api/classes",
                    json={
                        "school_id": school_id,
                        "name": detected_info.class_name,
                        "grade_level": grade_level,
                        "school_year": school_year,
                        "teacher_id": teacher_id
                    }
                )

                if response.status_code in (200, 201):
                    data = response.json()
                    class_id = data['id']

                    # Schueler hinzufuegen
                    if detected_info.students:
                        await self._bulk_create_students(
                            class_id,
                            detected_info.students
                        )

                    return SchoolClass(
                        id=class_id,
                        school_id=school_id,
                        name=detected_info.class_name,
                        grade_level=grade_level,
                        school_year=school_year,
                        teacher_id=teacher_id,
                        student_count=len(detected_info.students)
                    )

        except Exception as e:
            print(f"[SchoolResolver] Create class error: {e}")

        # Fallback: Lokale Klasse
        import uuid
        class_id = str(uuid.uuid4())
        school_class = SchoolClass(
            id=class_id,
            school_id=school_id,
            name=detected_info.class_name,
            grade_level=grade_level,
            school_year=school_year,
            teacher_id=teacher_id,
            student_count=len(detected_info.students)
        )
        self._local_classes[class_id] = school_class
        return school_class

    async def _bulk_create_students(
        self,
        class_id: str,
        students: List[Dict[str, str]]
    ) -> List[Student]:
        """Erstellt mehrere Schueler auf einmal."""
        created = []

        try:
            async with httpx.AsyncClient(timeout=10.0) as client:
                response = await client.post(
                    f"{self.school_service_url}/api/classes/{class_id}/students/bulk",
                    json={
                        "students": [
                            {
                                "first_name": s.get("firstName", s.get("first_name", "")),
                                "last_name": s.get("lastName", s.get("last_name", ""))
                            }
                            for s in students
                        ]
                    }
                )

                if response.status_code in (200, 201):
                    data = response.json()
                    created = [
                        Student(
                            id=s['id'],
                            class_id=class_id,
                            first_name=s['first_name'],
                            last_name=s.get('last_name', '')
                        )
                        for s in data.get('students', [])
                    ]

        except Exception as e:
            print(f"[SchoolResolver] Bulk create students error: {e}")

        return created

    # =========================================================================
    # CONTEXT MANAGEMENT
    # =========================================================================

    async def get_teacher_context(self, teacher_id: str) -> SchoolContext:
        """
        Holt den vollstaendigen Schulkontext eines Lehrers.

        Beinhaltet Schule, Klassen und aktuelles Schuljahr.
        """
        context = SchoolContext(teacher_id=teacher_id)

        # Klassen laden
        classes = await self.get_classes_for_teacher(teacher_id)
        context.classes = classes

        # Schule aus erster Klasse ableiten
        if classes and classes[0].school_id:
            schools = await self.search_schools()
            for school in schools:
                if school.id == classes[0].school_id:
                    context.school = school
                    break

        return context


# Singleton
_school_resolver: Optional[SchoolResolver] = None


def get_school_resolver() -> SchoolResolver:
    """Gibt die Singleton-Instanz des SchoolResolvers zurueck."""
    global _school_resolver
    if _school_resolver is None:
        _school_resolver = SchoolResolver()
    return _school_resolver
