# ==============================================
# Breakpilot Drive - Unit Definition CRUD Routes
# ==============================================
# Endpoints for creating, updating, deleting, and validating
# unit definitions. Extracted from unit_routes.py for file-size compliance.

from fastapi import APIRouter, HTTPException, Query, Depends
from typing import Optional, Dict, Any
from datetime import datetime
import logging

from .models import (
    UnitDefinitionResponse,
    CreateUnitRequest,
    UpdateUnitRequest,
    ValidationResult,
)
from .helpers import (
    get_optional_current_user,
    get_unit_database,
    validate_unit_definition,
)

logger = logging.getLogger(__name__)

router = APIRouter(prefix="/api/units", tags=["Breakpilot Units"])


@router.post("/definitions", response_model=UnitDefinitionResponse)
async def create_unit_definition(
    request_data: CreateUnitRequest,
    user: Optional[Dict[str, Any]] = Depends(get_optional_current_user)
) -> UnitDefinitionResponse:
    """
    Create a new unit definition.

    - Validates unit structure
    - Saves to database or JSON file
    - Returns created unit
    """
    import json
    from pathlib import Path

    # Build full definition
    definition = {
        "unit_id": request_data.unit_id,
        "template": request_data.template,
        "version": request_data.version,
        "locale": request_data.locale,
        "grade_band": request_data.grade_band,
        "duration_minutes": request_data.duration_minutes,
        "difficulty": request_data.difficulty,
        "subject": request_data.subject,
        "topic": request_data.topic,
        "learning_objectives": request_data.learning_objectives,
        "stops": request_data.stops,
        "precheck": request_data.precheck or {
            "question_set_id": f"{request_data.unit_id}_precheck",
            "required": True,
            "time_limit_seconds": 120
        },
        "postcheck": request_data.postcheck or {
            "question_set_id": f"{request_data.unit_id}_postcheck",
            "required": True,
            "time_limit_seconds": 180
        },
        "teacher_controls": request_data.teacher_controls or {
            "allow_skip": True,
            "allow_replay": True,
            "max_time_per_stop_sec": 90,
            "show_hints": True,
            "require_precheck": True,
            "require_postcheck": True
        },
        "assets": request_data.assets or {},
        "metadata": request_data.metadata or {
            "author": user.get("email", "Unknown") if user else "Unknown",
            "created": datetime.utcnow().isoformat(),
            "curriculum_reference": ""
        }
    }

    # Validate
    validation = validate_unit_definition(definition)
    if not validation.valid:
        error_msgs = [f"{e.field}: {e.message}" for e in validation.errors]
        raise HTTPException(status_code=400, detail=f"Validierung fehlgeschlagen: {'; '.join(error_msgs)}")

    # Check if unit_id already exists
    db = await get_unit_database()
    if db:
        try:
            existing = await db.get_unit_definition(request_data.unit_id)
            if existing:
                raise HTTPException(status_code=409, detail=f"Unit existiert bereits: {request_data.unit_id}")

            # Save to database
            await db.create_unit_definition(
                unit_id=request_data.unit_id,
                template=request_data.template,
                version=request_data.version,
                locale=request_data.locale,
                grade_band=request_data.grade_band,
                duration_minutes=request_data.duration_minutes,
                difficulty=request_data.difficulty,
                definition=definition,
                status=request_data.status
            )
            logger.info(f"Unit created in database: {request_data.unit_id}")
        except HTTPException:
            raise
        except Exception as e:
            logger.warning(f"Database save failed, using JSON fallback: {e}")
            # Fallback to JSON
            units_dir = Path(__file__).parent / "data" / "units"
            units_dir.mkdir(parents=True, exist_ok=True)
            json_path = units_dir / f"{request_data.unit_id}.json"
            if json_path.exists():
                raise HTTPException(status_code=409, detail=f"Unit existiert bereits: {request_data.unit_id}")
            with open(json_path, "w", encoding="utf-8") as f:
                json.dump(definition, f, ensure_ascii=False, indent=2)
            logger.info(f"Unit created as JSON: {json_path}")
    else:
        # JSON only mode
        units_dir = Path(__file__).parent / "data" / "units"
        units_dir.mkdir(parents=True, exist_ok=True)
        json_path = units_dir / f"{request_data.unit_id}.json"
        if json_path.exists():
            raise HTTPException(status_code=409, detail=f"Unit existiert bereits: {request_data.unit_id}")
        with open(json_path, "w", encoding="utf-8") as f:
            json.dump(definition, f, ensure_ascii=False, indent=2)
        logger.info(f"Unit created as JSON: {json_path}")

    return UnitDefinitionResponse(
        unit_id=request_data.unit_id,
        template=request_data.template,
        version=request_data.version,
        locale=request_data.locale,
        grade_band=request_data.grade_band,
        duration_minutes=request_data.duration_minutes,
        difficulty=request_data.difficulty,
        definition=definition
    )


@router.put("/definitions/{unit_id}", response_model=UnitDefinitionResponse)
async def update_unit_definition(
    unit_id: str,
    request_data: UpdateUnitRequest,
    user: Optional[Dict[str, Any]] = Depends(get_optional_current_user)
) -> UnitDefinitionResponse:
    """
    Update an existing unit definition.

    - Merges updates with existing definition
    - Re-validates
    - Saves updated version
    """
    import json
    from pathlib import Path

    # Get existing unit
    db = await get_unit_database()
    existing = None

    if db:
        try:
            existing = await db.get_unit_definition(unit_id)
        except Exception as e:
            logger.warning(f"Database read failed: {e}")

    if not existing:
        # Try JSON file
        json_path = Path(__file__).parent / "data" / "units" / f"{unit_id}.json"
        if json_path.exists():
            with open(json_path, "r", encoding="utf-8") as f:
                file_data = json.load(f)
                existing = {
                    "unit_id": file_data.get("unit_id"),
                    "template": file_data.get("template"),
                    "version": file_data.get("version", "1.0.0"),
                    "locale": file_data.get("locale", ["de-DE"]),
                    "grade_band": file_data.get("grade_band", []),
                    "duration_minutes": file_data.get("duration_minutes", 8),
                    "difficulty": file_data.get("difficulty", "base"),
                    "definition": file_data
                }

    if not existing:
        raise HTTPException(status_code=404, detail=f"Unit nicht gefunden: {unit_id}")

    # Merge updates into existing definition
    definition = existing.get("definition", {})
    update_dict = request_data.model_dump(exclude_unset=True)

    for key, value in update_dict.items():
        if value is not None:
            definition[key] = value

    # Validate updated definition
    validation = validate_unit_definition(definition)
    if not validation.valid:
        error_msgs = [f"{e.field}: {e.message}" for e in validation.errors]
        raise HTTPException(status_code=400, detail=f"Validierung fehlgeschlagen: {'; '.join(error_msgs)}")

    # Save
    if db:
        try:
            await db.update_unit_definition(
                unit_id=unit_id,
                version=definition.get("version"),
                locale=definition.get("locale"),
                grade_band=definition.get("grade_band"),
                duration_minutes=definition.get("duration_minutes"),
                difficulty=definition.get("difficulty"),
                definition=definition,
                status=update_dict.get("status")
            )
            logger.info(f"Unit updated in database: {unit_id}")
        except Exception as e:
            logger.warning(f"Database update failed, using JSON: {e}")
            json_path = Path(__file__).parent / "data" / "units" / f"{unit_id}.json"
            with open(json_path, "w", encoding="utf-8") as f:
                json.dump(definition, f, ensure_ascii=False, indent=2)
    else:
        json_path = Path(__file__).parent / "data" / "units" / f"{unit_id}.json"
        with open(json_path, "w", encoding="utf-8") as f:
            json.dump(definition, f, ensure_ascii=False, indent=2)
        logger.info(f"Unit updated as JSON: {json_path}")

    return UnitDefinitionResponse(
        unit_id=unit_id,
        template=definition.get("template", existing.get("template")),
        version=definition.get("version", existing.get("version", "1.0.0")),
        locale=definition.get("locale", existing.get("locale", ["de-DE"])),
        grade_band=definition.get("grade_band", existing.get("grade_band", [])),
        duration_minutes=definition.get("duration_minutes", existing.get("duration_minutes", 8)),
        difficulty=definition.get("difficulty", existing.get("difficulty", "base")),
        definition=definition
    )


@router.delete("/definitions/{unit_id}")
async def delete_unit_definition(
    unit_id: str,
    force: bool = Query(False, description="Force delete even if published"),
    user: Optional[Dict[str, Any]] = Depends(get_optional_current_user)
) -> Dict[str, Any]:
    """
    Delete a unit definition.

    - By default, only drafts can be deleted
    - Use force=true to delete published units
    """
    from pathlib import Path

    db = await get_unit_database()
    deleted = False

    if db:
        try:
            existing = await db.get_unit_definition(unit_id)
            if existing:
                status = existing.get("status", "draft")
                if status == "published" and not force:
                    raise HTTPException(
                        status_code=400,
                        detail="Veroeffentlichte Units koennen nicht geloescht werden. Verwende force=true."
                    )
                await db.delete_unit_definition(unit_id)
                deleted = True
                logger.info(f"Unit deleted from database: {unit_id}")
        except HTTPException:
            raise
        except Exception as e:
            logger.warning(f"Database delete failed: {e}")

    # Also check JSON file
    json_path = Path(__file__).parent / "data" / "units" / f"{unit_id}.json"
    if json_path.exists():
        json_path.unlink()
        deleted = True
        logger.info(f"Unit JSON deleted: {json_path}")

    if not deleted:
        raise HTTPException(status_code=404, detail=f"Unit nicht gefunden: {unit_id}")

    return {"success": True, "unit_id": unit_id, "message": "Unit geloescht"}


@router.post("/definitions/validate", response_model=ValidationResult)
async def validate_unit(
    unit_data: Dict[str, Any],
    user: Optional[Dict[str, Any]] = Depends(get_optional_current_user)
) -> ValidationResult:
    """
    Validate a unit definition without saving.

    Returns validation result with errors and warnings.
    """
    return validate_unit_definition(unit_data)
