from __future__ import annotations
from pydantic import BaseModel, Field
from typing import List, Dict, Optional
from pathlib import Path
from datetime import datetime
import uuid
import json
import threading

# Basisverzeichnis für Arbeitsblätter & Lerneinheiten
BASE_DIR = Path.home() / "Arbeitsblaetter"
LEARNING_UNITS_DIR = BASE_DIR / "Lerneinheiten"
LEARNING_UNITS_FILE = LEARNING_UNITS_DIR / "learning_units.json"

# Thread-Lock, damit Dateizugriffe sicher bleiben
_lock = threading.Lock()


class LearningUnitBase(BaseModel):
    title: str = Field(..., description="Titel der Lerneinheit, z.B. 'Das Auge – Klasse 7'")
    description: Optional[str] = Field(None, description="Freitext-Beschreibung")
    topic: Optional[str] = Field(None, description="Kurz-Thema, z.B. 'Auge'")
    grade_level: Optional[str] = Field(None, description="Klassenstufe, z.B. '7'")
    language: Optional[str] = Field("de", description="Hauptsprache der Lerneinheit (z.B. 'de', 'tr')")
    worksheet_files: List[str] = Field(
        default_factory=list,
        description="Liste der zugeordneten Arbeitsblatt-Dateien (Basenames oder Pfade)"
    )
    status: str = Field(
        "raw",
        description="Pipeline-Status: raw, cleaned, qa_generated, mc_generated, cloze_generated"
    )


class LearningUnitCreate(LearningUnitBase):
    """Payload zum Erstellen einer neuen Lerneinheit."""
    pass


class LearningUnitUpdate(BaseModel):
    """Teil-Update für eine Lerneinheit."""
    title: Optional[str] = None
    description: Optional[str] = None
    topic: Optional[str] = None
    grade_level: Optional[str] = None
    language: Optional[str] = None
    worksheet_files: Optional[List[str]] = None
    status: Optional[str] = None


class LearningUnit(LearningUnitBase):
    id: str
    created_at: datetime
    updated_at: datetime

    @classmethod
    def from_dict(cls, data: Dict) -> "LearningUnit":
        data = data.copy()
        if isinstance(data.get("created_at"), str):
            data["created_at"] = datetime.fromisoformat(data["created_at"])
        if isinstance(data.get("updated_at"), str):
            data["updated_at"] = datetime.fromisoformat(data["updated_at"])
        return cls(**data)

    def to_dict(self) -> Dict:
        d = self.dict()
        d["created_at"] = self.created_at.isoformat()
        d["updated_at"] = self.updated_at.isoformat()
        return d


def _ensure_storage():
    """Sorgt dafür, dass der Ordner und die JSON-Datei existieren."""
    LEARNING_UNITS_DIR.mkdir(parents=True, exist_ok=True)
    if not LEARNING_UNITS_FILE.exists():
        with LEARNING_UNITS_FILE.open("w", encoding="utf-8") as f:
            json.dump({}, f)


def _load_all_units() -> Dict[str, Dict]:
    _ensure_storage()
    with LEARNING_UNITS_FILE.open("r", encoding="utf-8") as f:
        try:
            data = json.load(f)
            if not isinstance(data, dict):
                return {}
            return data
        except json.JSONDecodeError:
            return {}


def _save_all_units(raw: Dict[str, Dict]) -> None:
    _ensure_storage()
    with LEARNING_UNITS_FILE.open("w", encoding="utf-8") as f:
        json.dump(raw, f, ensure_ascii=False, indent=2)


def list_learning_units() -> List[LearningUnit]:
    with _lock:
        raw = _load_all_units()
        return [LearningUnit.from_dict(v) for v in raw.values()]


def get_learning_unit(unit_id: str) -> Optional[LearningUnit]:
    with _lock:
        raw = _load_all_units()
        data = raw.get(unit_id)
        if not data:
            return None
        return LearningUnit.from_dict(data)


def create_learning_unit(payload: LearningUnitCreate) -> LearningUnit:
    now = datetime.utcnow()
    lu = LearningUnit(
        id=str(uuid.uuid4()),
        created_at=now,
        updated_at=now,
        **payload.dict()
    )
    with _lock:
        raw = _load_all_units()
        raw[lu.id] = lu.to_dict()
        _save_all_units(raw)
    return lu


def update_learning_unit(unit_id: str, payload: LearningUnitUpdate) -> Optional[LearningUnit]:
    with _lock:
        raw = _load_all_units()
        existing = raw.get(unit_id)
        if not existing:
            return None

        lu = LearningUnit.from_dict(existing)
        update_data = payload.dict(exclude_unset=True)

        for field, value in update_data.items():
            setattr(lu, field, value)

        lu.updated_at = datetime.utcnow()
        raw[lu.id] = lu.to_dict()
        _save_all_units(raw)
        return lu


def delete_learning_unit(unit_id: str) -> bool:
    with _lock:
        raw = _load_all_units()
        if unit_id not in raw:
            return False
        del raw[unit_id]
        _save_all_units(raw)
        return True


def attach_worksheets(unit_id: str, worksheet_files: List[str]) -> Optional[LearningUnit]:
    """
    Hängt eine Liste von Arbeitsblatt-Dateien an eine bestehende Lerneinheit an.
    Doppelte Einträge werden vermieden.
    """
    with _lock:
        raw = _load_all_units()
        existing = raw.get(unit_id)
        if not existing:
            return None

        lu = LearningUnit.from_dict(existing)
        current_set = set(lu.worksheet_files)
        for f in worksheet_files:
            current_set.add(f)
        lu.worksheet_files = sorted(current_set)
        lu.updated_at = datetime.utcnow()

        raw[lu.id] = lu.to_dict()
        _save_all_units(raw)
        return lu

