# ==============================================
# Breakpilot Drive - Unit API Helpers
# ==============================================
# Auth, database, token, and validation helpers for the Unit API.
# Extracted from unit_api.py for file-size compliance.

from fastapi import HTTPException, Request
from typing import Optional, Dict, Any, List
from datetime import datetime, timedelta
import os
import logging
import jwt

from .models import ValidationError, ValidationResult

logger = logging.getLogger(__name__)

# Feature flags
USE_DATABASE = os.getenv("GAME_USE_DATABASE", "true").lower() == "true"
REQUIRE_AUTH = os.getenv("GAME_REQUIRE_AUTH", "false").lower() == "true"
SECRET_KEY = os.getenv("JWT_SECRET_KEY", "dev-secret-key-change-in-production")


# ==============================================
# Auth Dependency (reuse from game_api)
# ==============================================

async def get_optional_current_user(request: Request) -> Optional[Dict[str, Any]]:
    """Optional auth dependency for Unit API."""
    if not REQUIRE_AUTH:
        return None

    try:
        from auth import get_current_user
        return await get_current_user(request)
    except ImportError:
        logger.warning("Auth module not available")
        return None
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Auth error: {e}")
        raise HTTPException(status_code=401, detail="Authentication failed")


# ==============================================
# Database Integration
# ==============================================

_unit_db = None

async def get_unit_database():
    """Get unit database instance with lazy initialization."""
    global _unit_db
    if not USE_DATABASE:
        return None
    if _unit_db is None:
        try:
            from unit.database import get_unit_db
            _unit_db = await get_unit_db()
            logger.info("Unit database initialized")
        except ImportError:
            logger.warning("Unit database module not available")
        except Exception as e:
            logger.warning(f"Unit database not available: {e}")
    return _unit_db


# ==============================================
# Token Helpers
# ==============================================

def create_session_token(session_id: str, student_id: str, expires_hours: int = 4) -> str:
    """Create a JWT session token for telemetry authentication."""
    payload = {
        "session_id": session_id,
        "student_id": student_id,
        "exp": datetime.utcnow() + timedelta(hours=expires_hours),
        "iat": datetime.utcnow(),
    }
    return jwt.encode(payload, SECRET_KEY, algorithm="HS256")


def verify_session_token(token: str) -> Optional[Dict[str, Any]]:
    """Verify a session token and return payload."""
    try:
        return jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
    except jwt.ExpiredSignatureError:
        return None
    except jwt.InvalidTokenError:
        return None


async def get_session_from_token(request: Request) -> Optional[Dict[str, Any]]:
    """Extract and verify session from Authorization header."""
    auth_header = request.headers.get("Authorization", "")
    if not auth_header.startswith("Bearer "):
        return None
    token = auth_header[7:]
    return verify_session_token(token)


# ==============================================
# Validation
# ==============================================

def validate_unit_definition(unit_data: Dict[str, Any]) -> ValidationResult:
    """
    Validate a unit definition structure.

    Returns validation result with errors and warnings.
    """
    errors: List[ValidationError] = []
    warnings: List[ValidationError] = []

    # Required fields
    if not unit_data.get("unit_id"):
        errors.append(ValidationError(field="unit_id", message="unit_id ist erforderlich"))

    if not unit_data.get("template"):
        errors.append(ValidationError(field="template", message="template ist erforderlich"))
    elif unit_data["template"] not in ["flight_path", "station_loop"]:
        errors.append(ValidationError(
            field="template",
            message="template muss 'flight_path' oder 'station_loop' sein"
        ))

    # Validate stops
    stops = unit_data.get("stops", [])
    if not stops:
        errors.append(ValidationError(field="stops", message="Mindestens 1 Stop erforderlich"))
    else:
        # Check minimum stops for flight_path
        if unit_data.get("template") == "flight_path" and len(stops) < 3:
            warnings.append(ValidationError(
                field="stops",
                message="FlightPath sollte mindestens 3 Stops haben",
                severity="warning"
            ))

        # Validate each stop
        stop_ids = set()
        for i, stop in enumerate(stops):
            if not stop.get("stop_id"):
                errors.append(ValidationError(
                    field=f"stops[{i}].stop_id",
                    message=f"Stop {i}: stop_id fehlt"
                ))
            else:
                if stop["stop_id"] in stop_ids:
                    errors.append(ValidationError(
                        field=f"stops[{i}].stop_id",
                        message=f"Stop {i}: Doppelte stop_id '{stop['stop_id']}'"
                    ))
                stop_ids.add(stop["stop_id"])

            # Check interaction type
            interaction = stop.get("interaction", {})
            if not interaction.get("type"):
                errors.append(ValidationError(
                    field=f"stops[{i}].interaction.type",
                    message=f"Stop {stop.get('stop_id', i)}: Interaktionstyp fehlt"
                ))
            elif interaction["type"] not in [
                "aim_and_pass", "slider_adjust", "slider_equivalence",
                "sequence_arrange", "toggle_switch", "drag_match",
                "error_find", "transfer_apply"
            ]:
                warnings.append(ValidationError(
                    field=f"stops[{i}].interaction.type",
                    message=f"Stop {stop.get('stop_id', i)}: Unbekannter Interaktionstyp '{interaction['type']}'",
                    severity="warning"
                ))

            # Check for label
            if not stop.get("label"):
                warnings.append(ValidationError(
                    field=f"stops[{i}].label",
                    message=f"Stop {stop.get('stop_id', i)}: Label fehlt",
                    severity="warning"
                ))

    # Validate duration
    duration = unit_data.get("duration_minutes", 0)
    if duration < 3 or duration > 20:
        warnings.append(ValidationError(
            field="duration_minutes",
            message="Dauer sollte zwischen 3 und 20 Minuten liegen",
            severity="warning"
        ))

    # Validate difficulty
    if unit_data.get("difficulty") and unit_data["difficulty"] not in ["base", "advanced"]:
        warnings.append(ValidationError(
            field="difficulty",
            message="difficulty sollte 'base' oder 'advanced' sein",
            severity="warning"
        ))

    return ValidationResult(
        valid=len(errors) == 0,
        errors=errors,
        warnings=warnings
    )
